Guides

Rate limits & caps

Each key can carry a monthly USD spend cap and its own rate limits. A key has none of them unless you set them.

How a cap behaves

  • Optional monthly USD cap per key, set in the console. It is checked before a request is dispatched, so a request over the cap never reaches a provider.
  • Over the cap the API returns 402 spend_cap_exceeded, with the month-to-date spend and the cap in the error body's metadata as spend_usd and cap_usd. Raise or clear the cap in the console and the next request goes through.
  • Month-to-date spend is compared in decimal arithmetic, so a request that sits exactly on the cap is refused rather than admitted by a rounding accident.

Caps protect against leaked keys and runaway loops, so we recommend one on every production key.

Rate limits

A key has no rate limit by default. You can set three on a key through the management API. The API keys page sets the spend cap only, and still shows a limit that is set:

  • Requests per minute (rate_limit_rpm). Checked before the request is read, so a refused request costs nothing.
  • Tokens per minute (rate_limit_tpm): the prompt and completion tokens of chat completions and embeddings, as reported in their usage. Tokens are counted when a request finishes, so the request that crosses the limit completes and the next one is refused. A failed request, or one whose usage is not reported, counts nothing.

Each allowance refills continuously over the minute. Over a limit the API returns 429 rate_limit_exceeded with a Retry-After header and metadata.reason set to key_rpm or key_tpm. Wait the number of seconds in Retry-After, then retry.

Concurrency and workspace controls

rate_limit_concurrency bounds requests in flight on a key. A refusal returns 429 rate_limit_exceeded with metadata.reason: key_concurrency and no timed Retry-After: wait for an existing request to finish before submitting more.

A workspace can also have an RPM limit and a monthly monthly_budget_usd. Reaching its settled-spend budget returns 402 workspace_budget_exceeded before dispatch. This is separate from a key cap: requests already in flight can settle above the workspace budget. The monthly window is UTC.

Video has a separate organisation-wide total: by default, up to 10 open video jobs across all of its workspaces. An operator can set a different total for the organisation; this is not a per-key setting. Queued and executing video jobs both count. Reaching the total returns 429 rate_limit_exceeded with metadata.reason: workspace_limit and a Retry-After hint, even though this video total covers the whole organisation.

Below that total, an accepted video may wait for shared provider capacity with status: pending and queued: true. Poll the accepted job; do not resubmit it. See Video generation for the ten-minute waiting deadline, reservation release and cancellation rules.

3D keeps its separate limit of two open jobs per workspace for each provider and model. An operator may also enable an organisation-wide abuse cap across job families; it is off by default and distinct from the video total, key concurrency and monthly spend caps.

Other 429s

A 429 without one of those reasons comes from the provider behind the model, or from another job admission control. For a refused submission, wait with exponential backoff, honouring Retry-After when present. If you already have an accepted job, keep polling that ID instead of submitting another generation.

Rate-limit headers

When a key has a limit, responses carry the matching headers: X-RateLimit-Limit-Requests, X-RateLimit-Remaining-Requests and X-RateLimit-Reset-Requests for requests per minute, and X-RateLimit-Limit-Tokens, X-RateLimit-Remaining-Tokens and X-RateLimit-Reset-Tokens for tokens per minute. They give the limit, what is left of it, and the whole seconds until it is full again. A key with no limit gets none of them.