API Reference
Rate Limits
The enforced rate-limit layers, client-visible headers, and 429 handling guidance
The API enforces several limits in sequence. Each can return 429. This page lists them and how to back off.
Enforced layers
| Layer | Default | On exceed |
|---|---|---|
| Per IP | 20 requests/second, burst 40 | 429 |
| Per-key RPM | 20 requests/minute, sliding 60s window | 429 with Retry-After: 60 |
| Per-key concurrency | 5 in-flight requests | 429 Concurrent request limit exceeded with Retry-After: 5 |
| Agent slots | 2 slots | 403 at 0 slots, 429 over the limit |
| Budget | EUR 50 monthly budget (api keys) | 429 with X-Budget-Remaining: 0 |
| Context cap | 800000 characters (about 200k tokens) | 413 |
The per-key RPM, concurrency, slot, and budget figures are the current defaults. To raise them, see Account limits.
Client-visible headers
Every /v1/* response carries the rate-limit headers. Retry-After is added on 429 and 503.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Concurrent-request limit (see note below) |
X-RateLimit-Remaining | Remaining capacity |
X-RateLimit-Reset | When the window resets |
Retry-After | Seconds to wait before retrying |
X-RateLimit-Limit currently reflects the concurrent-request limit, not requests per minute. Do not read it as RPM.
Handling 429
When you receive a 429:
- If
Retry-Afteris present, wait that many seconds, then retry. - Otherwise back off exponentially with jitter.
Do not retry 400, 401, 403, or 422. Those are client errors and a retry will fail the same way. See Errors for the status table.
Example backoff
import time, random
def call_with_retry(do_request, max_attempts=5):
for attempt in range(max_attempts):
resp = do_request()
if resp.status_code != 429:
return resp
retry_after = resp.headers.get("Retry-After")
if retry_after is not None:
time.sleep(float(retry_after))
else:
time.sleep((2 ** attempt) + random.random())
return resp