Every API key has a per-minute request budget. Exceeding it returns
429 rate_limited with a Retry-After header telling you when the
window resets.
Defaults
| Setting | Default | Range |
|---|---|---|
| Instance-wide default | 60 req/min | per-deploy |
| Per-key override | none | any positive integer (the dashboard form suggests up to 10,000) |
The per-key override (api_keys.rate_limit_per_minute) wins over the
instance default. Set it on a key when minting if you know the
integration needs more headroom — heavy-volume reporting jobs, bulk
record imports, etc.
Response headers
Every authenticated response that passes API-key validation — success or error — carries the current bucket state:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | The effective limit for this key |
X-RateLimit-Remaining | Requests left in the current minute window |
X-RateLimit-Reset | Unix epoch seconds when the window resets |
On a 429 you also get:
| Header | Meaning |
|---|---|
Retry-After | Seconds to wait before retrying (always ≥ 1) |
How to behave
- Watch
X-RateLimit-Remaining. When it drops to 0, queue further requests untilX-RateLimit-Reset. - On 429, sleep
Retry-Afterseconds and retry. Don't busy-loop. - For sustained high volume, request a per-key override rather than spraying retries — sustained 429s show up in our observability and may trigger investigation.
Example: handle 429 with backoff
async function call(request) {
for (let attempt = 1; attempt <= 3; attempt++) {
const response = await fetch(request)
// Anything other than 429 — success or a real error — is final.
if (response.status !== 429) return response
// 429 means "slow down". Retry-After says how many seconds to wait.
const seconds = Number(response.headers.get('Retry-After') ?? 1)
await new Promise((resolve) => setTimeout(resolve, seconds * 1000))
}
throw new Error('still rate-limited after 3 attempts')
}Bursts vs. sustained
The bucket is per-minute. You can burst the full limit at the start of a window — 60 requests in the first second is fine. The next 59 seconds return 429s until the window rolls. If you need true bursting (1000 in 10 seconds, then quiet for an hour), ask for an override and pace your own sender.