DocsErrors & Rate Limits
Errors & Limits
Error Envelope and Rate Limits
All failures use a consistent error object. Use status code + error.code to implement safe retry and fallback behavior.
Error envelope
REST failures return { "error": { ... } } with optional details payload.
jsonError shape9 lines
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please retry shortly.",
"details": {
"retry_after": 12
}
}
}Status and code mapping
| HTTP | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Input shape or field values are invalid. |
| 401 | UNAUTHORIZED | Missing, malformed, or expired API key. |
| 403 | FORBIDDEN | Key revoked or not allowed for requested org resource. |
| 404 | NOT_FOUND | Resource id does not exist or is not accessible to the org. |
| 412 | PRECONDITION_FAILED | Audio is unavailable for current resource state. |
| 429 | RATE_LIMITED | Route limit exceeded for current window. |
| 500 | INTERNAL_ERROR | Unexpected server error. |
Rate limit rules
| Route | Limit | Notes |
|---|---|---|
| POST /api/v1/generations | 20 requests / 60 seconds | 429 responses include Retry-After in seconds. |
| POST /api/v1/voices | 5 requests / 60 seconds | Use batching/queueing for bulk voice ingest. |
| GET /api/v1/* | 120 requests / 60 seconds | Covers authenticated GET endpoints under /api/v1. |
Backoff recommendation
On 429, respect Retry-After when present. On 5xx, use bounded exponential backoff with jitter and idempotent retry behavior.
Retry snippet
tsRetry on 4297 lines
const retryAfter = Number(response.headers.get("Retry-After") ?? "0");
const delay = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1000 : 1000;
if (response.status === 429) {
await new Promise((resolve) => setTimeout(resolve, delay));
// retry request
}Search documentation
Find pages, endpoints, and sections.