Rate limits
Reference article: Part of the API reference.
Each API key can send about 1,200 requests per minute. The limit protects your organization and others from runaway clients. It isn't a quota: allowance refills continuously, so a steady 20 requests per second never hits it, and a key that has been quiet can send a burst.
Limits apply per key, so one busy integration can't use up another's allowance. That's another reason to give each integration its own key.
Rate limit headers
Every authenticated response says where the key stands:
| Header | Meaning |
|---|---|
RateLimit-Limit |
Requests allowed per minute. |
RateLimit-Remaining |
Requests you can send right now. |
RateLimit-Reset |
Seconds until the allowance is full again. |
Retry-After |
On a 429 only: seconds to wait before retrying. |
HTTP/2 200
RateLimit-Limit: 1200
RateLimit-Remaining: 1187
RateLimit-Reset: 1
Request-Id: req_Hq4tWm9Lx2Vb7Nc5Rz8Ka1Pd
When you're limited
A limited request fails with 429, the type rate_limit_error, and the code rate_limited. Wait for Retry-After seconds, then retry. Rate-limited requests are logged like any other, so they show up on the Developers page.
::: code-group
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
export const withRetry = async (send: () => Promise<Response>, attempts = 5): Promise<Response> => {
for (let attempt = 1; ; attempt++) {
const response = await send()
const retryable = response.status === 429 || response.status >= 500
if (!retryable || attempt === attempts) return response
const retryAfter = Number(response.headers.get('Retry-After'))
const backoff = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: Math.min(30_000, 500 * 2 ** attempt) * (0.5 + Math.random() / 2)
await sleep(backoff)
}
}
const response = await withRetry(() =>
fetch('https://api.gonimbus.ai/v1/whoami', {
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
}),
)
import random
import time
import requests
def with_retry(send, attempts=5):
for attempt in range(1, attempts + 1):
response = send()
retryable = response.status_code == 429 or response.status_code >= 500
if not retryable or attempt == attempts:
return response
retry_after = response.headers.get("Retry-After")
if retry_after and retry_after.isdigit():
delay = int(retry_after)
else:
delay = min(30, 0.5 * 2**attempt) * (0.5 + random.random() / 2)
time.sleep(delay)
response = with_retry(
lambda: requests.get(
"https://api.gonimbus.ai/v1/whoami",
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
)
:::
Staying under the limit
- Spread work out. Queue background jobs instead of sending them all at once.
- Don't poll hard. Where the API offers events, subscribe to webhooks instead of polling.
- Retry with backoff. Honour
Retry-After, and add jitter so many workers don't retry in lockstep. - Split integrations across keys. Each key has its own allowance.
FAQ
Is the limit per key or per organization?
Per key.
Can I get a higher limit?
Contact support with what you're building and the request rate you need.
Do requests with a bad key count against my limit?
No. The limit applies once a key is recognized, so requests with a missing or invalid key don't use any key's allowance.
Why did I get more requests through than the limit?
Allowance is tracked by each API server, so at times you may get somewhat more through than the stated limit. Don't rely on it: design for the stated limit and follow the headers.
Do rate-limited requests use NTUs?
No. A 429 is refused before any work starts.