Errors & Limits
All errors use a consistent JSON envelope with a machine-readable code and request_id for support.
Error envelope
{
"error": {
"code": "insufficient_credits",
"message": "Insufficient credits",
"request_id": "uuid"
}
}
Error codes
| Code | Status | Meaning |
|---|---|---|
| unauthorized | 401 | Missing Authorization header |
| invalid_key | 401 | Key does not start with oo_live_ |
| key_not_found | 401 | Revoked or unknown API key |
| org_inactive | 403 | Organization suspended or closed |
| scope_denied | 403 | Key lacks the required scope |
| model_not_allowed | 403 | Model outside your plan or key allowlist |
| insufficient_credits | 402 | Not enough credits for the request |
| rate_limit_exceeded | 429 | Per-key per-minute limit hit — retry after 60s |
| validation_error | 400 | Malformed body or unsupported model for endpoint |
| content_policy | 422 | Prompt blocked by content policy |
| idempotency_conflict | 422 | Idempotency-Key reused with a different payload |
| idempotency_in_progress | 409 | A request with this Idempotency-Key is still running |
Send Idempotency-Key (8–256 chars) on POSTs. Replays return the stored response. 402s include checkout_url.
Responses include X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. 429s include Retry-After.
Rate limits
| Tier | Limit |
|---|---|
| standard | 60 requests / minute / key |
| elevated | 300 requests / minute / key |
Exceeded limits return 429 with rate_limit_exceeded.