Rate limits
Rate limits protect service availability and latency. Requests that exceed a
limit return 429 Too Many Requests with a Retry-After header.
What's limited
Requests can be limited for two reasons:
| Condition | Response |
|---|---|
| Workspace request rate exceeded | 429 rate_limit_exceeded |
| Service temporarily at capacity | 429 service_busy |
Your workspace has a sustained request-rate limit. If you need a committed rate or a higher limit, contact us.
Additional constraints:
- Rate limits are workspace-wide. All API keys in a workspace share the same request-rate limit and credit balance.
- Short bursts may still be limited. Design clients to handle
429responses even when average traffic is below the stated sustained rate. - Token limits are model-specific. Prompt plus completion must fit the
model's 4,096-token context window. Requests over that limit
return
400 Bad Request.
When you hit a limit
Over-limit requests fail fast with 429, code rate_limit_exceeded, and a
Retry-After header (in seconds):
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 1
{"error": {"message": "You have exceeded your workspace's request rate. Slow down and retry, or contact support for a higher sustained limit.", "type": "rate_limit_exceeded", "code": "rate_limit_exceeded"}}
A 429 service_busy response indicates temporary service capacity pressure.
Handle it in the same way: honor Retry-After and retry with backoff. See
Errors for details.
An out-of-credit workspace returns 402 insufficient_quota. Add credit
before retrying. See Errors.
Backing off well
Wait at least as long as Retry-After, use exponential backoff with jitter for
subsequent attempts, and cap the number of retries:
import random
import time
from openai import APIStatusError
def with_backoff(call, max_attempts=5):
for attempt in range(max_attempts):
try:
return call()
except APIStatusError as err:
if err.status_code not in (429, 502, 503) or attempt == max_attempts - 1:
raise
retry_after = float(err.response.headers.get("retry-after", 1))
# Full jitter: sleep somewhere in [retry_after, retry_after + 2^attempt)
time.sleep(retry_after + random.uniform(0, 2 ** attempt))
For applications with multiple workers, enforce a shared client-side concurrency limit. This is more predictable than independent retry loops in each worker.
Watching your usage
The Console's usage page shows completed requests and token
volumes. It does not include throttled requests, so monitor 429 responses in
your application logs and metrics.