Limits
Two kinds of limits apply: request rates and field sizes. Both return machine-readable errors, so your code can back off or fix the request.
Rate limits
The API enforces 10,000 requests per minute per account across all /api/v2 endpoints, shared by all API keys and dashboard sessions on the account. Authenticated responses include tracking headers:
Every figure on this page is the allowance you can rely on, not an exact ceiling: you will never be throttled below it, and in some deployments we allow more. Design against the published number and use the response headers below for the live figure.
Past the limit, requests return 429 with a Retry-After header (seconds to wait):
The SDKs retry 429 and 5xx responses with exponential backoff for idempotent methods (GET, PUT, DELETE), and for the run-creating POSTs, which carry an idempotency key so a retry can never start a second run. Any other POST or PATCH is not retried, to prevent duplicate side effects. A RateLimitError only reaches your code once all retries are exhausted.
Idempotency
A run costs money, so a request that times out must never leave you guessing whether you were charged. Send an Idempotency-Key header on any run-creating POST and retrying it returns the run the first attempt made, instead of starting a second one:
Supported on POST /runs, POST /runs/with-files, POST /runs/{id}/reply, POST /runs/{id}/reply/with-files, and POST /tasks/{id}/runs.
- Same key, same request →
200with the original run's current state and anIdempotent-Replay: trueheader. Safe to repeat as often as you like. - Same key, different request →
409witherror.details.error_code = "idempotency_key_reuse". A key is never silently replayed against a call you did not make. - Keys last 24 hours and are scoped to your account, so two accounts can use the same key string without interfering.
- Failed requests do not bind the key. A
402,429, or500leaves the key free — fix the cause and retry with the same one.
The SDKs generate a key for every runs.create, runs.reply, and tasks.run automatically, which is what makes their retries safe. Pass your own when a retry must survive a process restart:
A replayed streaming call is answered as JSON rather than SSE — a run that already exists has no fresh stream to emit — and the SDKs handle that for you by joining the existing run's stream. If that run has already finished there is nothing to join, so they raise with the run id (idempotent_replay_terminal); fetch its result with runs.get(id).
Multi-tenant: per-end-user rate limits
Rate-limit each end-user's agent turns (run starts and replies) independently, so one end-user bursting can't consume the account:
Past the rate, run creation and replies for that user_id return 429 with error.details.error_code = "END_USER_RATE_LIMITED" (plus end_user_id, limit_per_minute, retry_after, and a Retry-After header). Other end-users and your own runs are unaffected. Off by default (null); send null to turn it off again. Related per-end-user run and cost caps: Users.
Advanced: auth endpoint limits (IP-based)
Login, registration, and password reset endpoints have a separate limit of 10 requests per minute per IP address:
POST /v1/auth/loginPOST /v1/auth/registerPOST /v1/auth/forgot-passwordPOST /v1/auth/reset-passwordPOST /v1/auth/verify-email
POST /api/v2/signup (agent-driven signup) has its own IP limit of 10 requests per minute.
Any other /api/v2 request we cannot authenticate — no key, an expired or revoked session, a key that does not exist — is throttled per IP, with an allowance of 120 requests per minute. Most of these can only return 401, so a working integration rarely reaches this limit; fix the credential rather than retrying. Verifying an unrecognised credential is metered by this same allowance — charged before the check and given back when it turns out to be a real account — so a burst of bad keys from one address is what exhausts it, not ordinary authenticated traffic. A few genuinely public endpoints (the plan catalogue, the agent-template list, and POST /api/v2/token) are also counted here, since they take no credential. Note that a credential you revoke keeps counting against the account it belonged to for up to ten seconds — rate-limit attribution is cached, so it catches up shortly after, and only then does the credential count against your IP instead. It is rejected with a 401 on every request throughout either way.
These endpoints do not require authentication, so limiting is keyed by IP rather than account, and the response uses a different format:
Field limits
Request fields have size and count caps:
Webhook payloads and inbound events are capped at 256 KB; larger requests return 413.
The metadata field accepts any JSON object under 10 KB serialized. Use it for IDs, labels, and lightweight state, not for large blobs or document content. When a field exceeds its limit, the API returns 422:
Next: Errors · Going Live
