Core concepts
Rate limits
Two budgets run at once: a per-minute burst and a per-day total. Both are scoped to your account and set by your plan.
Limits by plan
| Plan | Requests per minute | Requests per day |
|---|---|---|
| Free | 60 | 5,000 |
| Starter | 90 | 12,000 |
| Pro | 120 | 25,000 |
| Crew | 240 | 60,000 |
| Company | 600 | 150,000 |
| Enterprise (all plans) | 1,200 | 500,000 |
The daily budget resets at 00:00 UTC. The burst window is one minute. Live and test keys are metered separately, so exercising the API with a test key does not eat into your production budget.
Any plan not listed — including a new one we add later — falls back to 60 requests per minute and 5,000 per day.
These are abuse rails, not your usage allowance
Rate limits exist to stop runaway loops and abuse. What you can actually do with the product is governed by your plan’s entitlements, not by these numbers. If a legitimate integration needs more headroom, talk to us — limits can be raised per account.
Reading your remaining budget
Every response tells you exactly where you stand:
HTTP/1.1 200 OK
X-Request-Id: req_b07b069f0a83492877e3fa31
X-RateLimit-Limit-Burst: 240
X-RateLimit-Remaining-Burst: 237
X-RateLimit-Limit-Daily: 60000
X-RateLimit-Remaining-Daily: 59781
X-RateLimit-Reset: 1785765300| Header | Sent on | Meaning |
|---|---|---|
X-RateLimit-Limit-Burst | every response | Your plan's ceiling for the current one-minute window. |
X-RateLimit-Remaining-Burst | every response | Requests left in the current one-minute window. |
X-RateLimit-Limit-Daily | every response | Your plan's ceiling for the current UTC day. |
X-RateLimit-Remaining-Daily | every response | Requests left today (resets at 00:00 UTC). |
X-RateLimit-Reset | every response | Unix seconds at which the burst window rolls over. |
Retry-After | 429 only | Seconds to wait before retrying. Never more than 60 for a burst rejection. |
When you go over
You get a 429 with the error type rate_limit_error and a Retry-After header. The message names which budget ran out, and X-RateLimit-Remaining-Daily tells you whether waiting a minute will help or whether you are done for the day.
Bursting does not burn your daily budget
Requests rejected by the per-minute limit do not count against your daily total. Hitting the burst ceiling costs you nothing but the wait — so a client that backs off correctly is never penalised for retrying.
Handling a 429
async function callWithRetry(url, init, attempt = 0) {
const res = await fetch(url, init);
if (res.status !== 429 || attempt >= 5) return res;
// Retry-After is authoritative. Add a little jitter so a fleet of
// workers does not all wake up in the same millisecond.
const wait = Number(res.headers.get("Retry-After") ?? 1);
const jitter = Math.random() * 250;
await new Promise((r) => setTimeout(r, wait * 1000 + jitter));
return callWithRetry(url, init, attempt + 1);
}- Honour
Retry-Afterrather than guessing. For a burst rejection it is never more than 60 seconds. - Add jitter. Without it, every worker that got a
429at the same moment retries at the same moment. - Cap your retries. If the daily budget is exhausted, backing off will not fix it before midnight UTC.
- Watch
X-RateLimit-Remaining-Dailyand slow down before you hit zero, rather than sprinting into the wall.
A separate limit applies before we read your key
There is also a per-IP limit applied ahead of authentication, which returns 429 with the code ip_throttled. It is an abuse rail against unauthenticated floods and sits well above the per-account limits, so a normal integration will never meet it — but if you route a very large number of clients through one IP, that is what you would be seeing.