How limits are applied
Rate limits are enforced independently per API key and per route. A burst of requests to one endpoint does not consume the budget for another. Limits reset on a rolling window.
Note
Response headers
Every successful response includes headers that report the current rate-limit state for the key and route combination.
| Header | Type | Description |
|---|---|---|
X-RateLimit-Limit | integer | Maximum requests allowed in the current window |
X-RateLimit-Remaining | integer | Requests remaining before throttling |
X-RateLimit-Reset | integer seconds | Seconds remaining until the current window resets |
Example response headers
HTTP/1.1 200 OK X-RateLimit-Limit: 100 X-RateLimit-Remaining: 87 X-RateLimit-Reset: 12 Content-Type: application/json
429 Too Many Requests
When the limit is exceeded, the API returns a 429 status with a machine-readable error body and updated rate-limit headers. Use X-RateLimit-Reset to determine when to retry.
429 response
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 12
Content-Type: application/json
{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED"
}Implementing backoff
Clients should implement exponential backoff with jitter for 429 responses. A simple strategy:
- On a 429, read the
X-RateLimit-Resetheader. - Wait at least that many seconds before retrying.
- If the header is missing, wait 1 second and double on each subsequent retry.
- Add random jitter (0–500ms) to avoid thundering-herd effects.
- Cap retries at a reasonable maximum (e.g., 5 attempts).
Backoff example (TypeScript)
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 5): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (err: any) {
if (err.status !== 429 || attempt === maxRetries - 1) throw err;
const resetSeconds = Number(err.headers?.["x-ratelimit-reset"]);
const delaySeconds =
Number.isFinite(resetSeconds) && resetSeconds > 0
? resetSeconds
: 2 ** attempt;
const jitter = Math.random() * 0.5;
await new Promise((r) => setTimeout(r, (delaySeconds + jitter) * 1000));
}
}
throw new Error("Unreachable");
}Tip
Best practices
- Monitor
X-RateLimit-Remainingproactively rather than waiting for 429s. - Batch operations where the API supports list or bulk endpoints.
- Use separate API keys for independent services so one service's traffic does not starve another.
- Log rate-limit headers in your observability pipeline to detect trends early.