Rate limits
Only endpoints that intentionally differ from the standard API carry a chip; the chip links to the note that explains the difference.
Every budget below renews on a fixed window and answers 429 when spent. Find your number in the table, check whether that 429 carries a Retry-After header, and react accordingly. A 402 is never a rate limit — it means your balance is empty, so top up instead of retrying.
/v1/chat/completions/api/dashboard/playground/chat/api/dashboard/loginYour budgets at a glance
| Surface | Limit | Scope | When exceeded |
|---|---|---|---|
| Inference (OpenAI + Anthropic) | Your key's rate_limit per minute (default 500; explicit 1..1000, anything else 400) | Per account — all keys combined | 429, no Retry-After; back off or ask support to raise it |
| Playground chat (dashboard session) | 20 requests/min | Per signed-in user | 429, no Retry-After |
| Concurrent requests at low balance | Up to $0.05: 1 in flight; up to $0.25: 3; above $0.25: unbounded | Per account | 429, no Retry-After; let requests finish or top up |
| Free-model fair-use (atmo/* promo) | 100M lifetime tokens per account; $1 lifetime deposits to unlock (both admin-configurable) | Per account | 429 naming the remedy; paid models unaffected |
| Sign-in + password step-up | 20 tries per IP + 8 per account per 15 min; 15-min lockout | Per IP and per account | 429 with Retry-After; wait the stated seconds |
| Signup email sends | 3 per email/hour; 20 per IP/hour; 90 global/day; 2700 global/month; 1-min resend cooldown (defaults) | Per email / IP / global | 429 code rate_limited with Retry-After + retry_after_seconds |
| Signup completion | 30 per IP/hour; 120 global/hour (defaults) | Per IP / global | Same 429 shape as email sends |
| Provider webhooks | 30/min per IP on every callback | Per client IP | 429 with Retry-After |
Your inference budget belongs to your account, not to any single key: every request counts against the owning user's per-minute window, so minting extra keys never multiplies it. Omit rate_limit when creating a key and it resolves to 500; an explicit value must be between 1 and 1000 — anything else (including 0 and negatives) is rejected with 400. The catalogue read (GET /v1/models) carries no per-minute budget.
What a 429 looks like
Inference refusals quote your account's own limit back at you. On the OpenAI surface:
{
"error": {
"message": "rate limit exceeded: 500 requests/min for your account (all keys combined) — wait a minute or contact support to raise it",
"type": "rate_limit_exceeded"
}
}The Anthropic surface carries the same message in its own envelope:
{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "rate limit exceeded: 500 requests/min for your account (all keys combined) — wait a minute or contact support to raise it"
}
}Playground refusals are shorter (rate limit exceeded with type rate_limit_exceeded), and tired-balance refusals say too many concurrent requests for current balance — wait for in-flight requests to complete or top up. Free-model refusals carry the promo message with type rate_limit_exceeded and code free_tier_quota_exceeded on the OpenAI surface (rate_limit_error on Anthropic). Signup refusals use code rate_limited.
| Who answers 429 | Retry-After? | Body signal |
|---|---|---|
| Inference, playground, low-balance concurrency, free-model quota, upstream passthrough | No — back off exponentially | OpenAI envelope (Anthropic envelope on /v1/messages) |
| Sign-in, password step-up, account-deletion confirm | Yes — wait the stated seconds | {"error": "..."} string plus the header |
| Signup register / resend / complete | Yes, plus retry_after_seconds in the body | {"error": {"code": "rate_limited", ...}} |
| Provider webhooks (sumopod, epusdt) | Yes — wait the stated seconds | {"error": "too many webhook calls"} |
X-RateLimit-* headers. The 429 itself — plus Retry-After where the table above says so — is the only rate signal.Staying under
Honor Retry-After wherever it is present; otherwise back off exponentially — the full retry pattern lives under Errors and is not repeated here. Keep concurrent requests serialized while your balance is thin, or top up past $0.25 to lift the concurrency cap entirely. Paid models are never gated by the free-model quota: a free-model 429 names its own remedy in the message.
429, 502 and 503 with exponential backoff. 402 means your balance is empty, so top up instead of retrying. Never retry 400, 401, 403 or 404.Where these numbers come from
These are the live gateway defaults; if one changes, this page changes with it.
| Number |
|---|
| Sliding 1-min window; legacy limits ≤ 0 fall back to the 500 default |
| 500 default on omit; explicit 1..1000, anything else → 400 |
| Per-user enforcement (all keys combined) |
| Playground 20/min |
| Concurrency 1 / 3 / unbounded |
| Sign-in 20 + 8, 15-min window + lockout |
| Retry-After senders (auth, signup, webhooks) |
| Signup quotas + 429 shape |
| Free-model quota + refusal shape |
| Upstream 429 passthrough |