Rate limits

Rate limits depend on your plan tier. Limits are enforced per API key and apply across the entire endpoint pool — not per endpoint.

Limits by plan

PlanPer-secondPer-minutePer-day
Trial26010,000
Hobby520050,000
Production503,0001,000,000
EnterpriseCustom — quoted to your traffic shape
💡
WebSocket connections and message volume have separate limits — see the WebSocket overview.

Rate-limit headers

Every response includes:

X-RateLimit-Limit: 200
X-RateLimit-Remaining: 184
X-RateLimit-Reset: 1700000000

X-RateLimit-Reset is a Unix timestamp in seconds. Inspect it on every response and back off pre-emptively when Remaining approaches zero.

When you exceed a limit

You'll get a 429 response:

HTTP/1.1 429 Too Many Requests
Retry-After: 5

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after 5 seconds.",
    "retry_after_seconds": 5,
    "request_id": "req_8f3a2b1c"
  }
}

Recommended retry pattern

Exponential backoff with jitter, respecting retry_after_seconds:

async function withRetry(fn, { maxAttempts = 5 } = {}) {
  let attempt = 0;
  while (true) {
    try { return await fn(); }
    catch (err) {
      attempt++;
      if (err.status !== 429 && err.status < 500) throw err;
      if (attempt >= maxAttempts) throw err;

      const serverHint = err.body?.error?.retry_after_seconds ?? 0;
      const exp = Math.min(2 ** attempt, 60);
      const jitter = Math.random() * 0.5 * exp;
      const sleep = Math.max(serverHint, exp + jitter) * 1000;
      await new Promise(r => setTimeout(r, sleep));
    }
  }
}
⚠️
Don't retry on 400, 401, 403, or 404 — these are client errors that won't fix themselves. Only retry on 429 and 5xx.