How Rate Limits Work
Requests are counted over a 15-minute window. When a window’s allowance is used up, further requests are refused with429 Too Many Requests until the window ends. A refused request is not run.
- A recognized API key is counted on its own, so one customer’s traffic never uses up another’s.
- Anything else is counted by IP address: calls with no key, and calls with a key the API cannot vouch for.
- A partner key is held to a ceiling of 1,000,000 requests per 15 minutes (about 1,100 a second). It is there to stop a runaway loop, not to meter a platform that serves hundreds of thousands of its own users.
RateLimit-Limit header of its response, so read it there instead of hard-coding a number.
Reading Rate Limit Headers
Responses that were counted include rate limit headers:RateLimit-Policy: the allowance and the length of the window in seconds (3000;w=900is 3,000 requests per 900 seconds)RateLimit-Limit: the requests allowed in the windowRateLimit-Remaining: the requests left in the windowRateLimit-Reset: the seconds until the window ends (a number of seconds to wait, not a timestamp)
X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are sent as well. The first two carry the same numbers. X-RateLimit-Reset does not: it is the time the window ends, in Unix seconds, not a number of seconds to wait. Read the RateLimit-* headers.
Use these to track your usage and slow down before you are refused.
Handling 429 Responses
Whichever limit you ran into, a refusal looks the same: aRetry-After header and the standard error envelope. Retry-After and error.retryAfter are the same number, in whole seconds (at least 1).
error.code tells you which limit it was:
RATE_LIMIT_EXCEEDED: the general limit for calls counted by IP address, the sign-in limit, or the limit on public embed endpointsRATE_LIMIT_API_KEY_EXCEEDED: the limit on a recognized API keyRATE_LIMIT_USER_EXCEEDED: the brake on one person’s use of one kind of operation, such as billing changes (20 a minute), creating widgets (120 a minute), buying extra credits (10 an hour) or replaying a notification delivery (5 a minute). It is separate from the allowance on your key, and it is counted across all of that person’s keys and sessions.error.details.operationnames the operation. Usage Limits lists them allCOST_LIMIT_EXCEEDED: a usage budget per hour or per day, not a count of requests.Retry-Afteris the end of the hour or day whose budget was used upCONCURRENCY_LIMIT_EXCEEDED: too many operations of yours are running at once. It has noRetry-After: retry once one of them has finished
error.details carries what is particular to the limit (the limit, and for some codes the operation or the budgets). Do not depend on a key that is not documented for its code.
A refusal never reaches the operation, so it is safe to retry. When you retry a
POST, send the same Idempotency-Key as the first attempt (see Idempotency).Implementation Example
Best Practices
- Honor
Retry-After- It is the time left until your counter starts over; retrying sooner is refused again - Monitor headers proactively - Slow down before hitting limits
- Implement exponential backoff - When a refusal has no
Retry-After, don’t retry immediately - Use batch endpoints - Reduce total request count
- Cache responses - Avoid redundant requests
- Spread requests - Don’t burst all at once