Rate limits
How much you can send, what the headers tell you, and how to back off correctly.
Requests are counted per API key in a rolling one-minute window. The default allowance is 1000 requests per hour, which the limiter spends as 16 per minute so one burst cannot exhaust an hour's budget.
Every response tells you where you stand, so you never have to guess:
| Header | Meaning |
|---|---|
RateLimit-Limit | Requests allowed in the current window. |
RateLimit-Remaining | Requests left in it. |
RateLimit-Reset | Seconds until the window resets. |
RateLimit-Policy | The policy in force, for example 16;w=60. |
Retry-After | On a 429 only. Seconds to wait. |
Handling a 429
A 429 carries code rate_limit_exceeded and a Retry-After header. Wait that long, then retry — do not retry immediately, and do not invent your own delay when the API has told you the right one.
import { CuteDynoError } from '@cutedyno/node';
try {
await cutedyno.posts.create(input);
} catch (error) {
if (error instanceof CuteDynoError && error.isRateLimit) {
await sleep((error.retryAfter ?? 60) * 1000);
// …then retry, with the same idempotency key.
}
}The Node SDK does this for you: 429 and 5xx are retried twice by default, honouring Retry-After, with exponential backoff and jitter when the header is absent. Raise or lower it with maxRetries.
Use the same idempotency key across those retries, or a retry can create a second post. See idempotency.
Staying under the limit
Use webhooks instead of polling. This is the big one. Polling ten posts every five seconds is 120 requests a minute against a 16 per minute limit; a post.published webhook is zero. Webhooks is the fix for almost every rate limit problem we see.
Batch accounts into one post. One POST /v1/posts with five accountIds is one request, publishes to five accounts, and gives you one status to track. Five separate posts are five requests and five things to reconcile.
Watch the headers rather than counting. Track RateLimit-Remaining and slow down as it approaches zero. The SDK will hand it to you on every response:
const cutedyno = new CuteDyno({
onRateLimit: ({ remaining, reset }) => {
if (remaining < 3) metrics.gauge('cutedyno.throttle_risk', reset);
},
});Serialise your workers. Ten workers each retrying in lockstep will hammer the same key. One queue with limited concurrency uses the same budget and finishes sooner.
Platform limits are separate
CuteDyno's limit governs calls to CuteDyno. The platforms have their own, and those apply to publishing, not to your API calls:
- TikTok caps direct posts per user per day.
- Instagram caps content publishing per account per rolling 24 hours.
- YouTube spends daily quota units per upload.
When a platform rejects a post for its own quota, the post fails with a platform error rather than a CuteDyno 429, and the message names the platform. Retrying immediately will not help; the platform quota resets on its own schedule. The per-platform pages under Platforms list the current caps.
Asking for more
If your workload genuinely needs a higher ceiling — a large migration, or a platform onboarding thousands of profiles at once — get in touch with your key prefix and the shape of the traffic. Limits are per key, so a bulk-import key can be raised without touching your production one.