Docs/Errors & retries
Errors & retries.
Every error response is a JSON envelope with a stable code, a human message, and a request_id you can quote in support. WebSocket errors arrive on the wire as the same envelope.
Envelope
json
{
"error": {
"code": "voice_not_found",
"message": "Voice 'arjun_2' is not in the catalogue. See /docs/voices.",
"param": "voice",
"request_id": "req_01HZF8K9XV..."
}
}
HTTP status codes
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | Body fails schema validation. param identifies the offending field. |
| 401 | invalid_api_key | Missing, malformed, or revoked key. |
| 403 | scope_denied | Key lacks permission for the requested voice, language, or IP range. |
| 404 | voice_not_found / language_unsupported | Requested resource does not exist. |
| 413 | input_too_long | Input exceeds 4 000 characters; chunk the text. |
| 429 | rate_limited | You're over the per-second or per-minute cap. Respect Retry-After. |
| 499 | client_disconnected | You closed the connection before audio finished. No charge. |
| 500 | internal_error | Transient. Retry with backoff; if persistent, page us with the request_id. |
| 503 | capacity_exhausted | Regional pool saturated. Retry on a different region or with backoff. |
Retry policy
Retry on 429, 500, 502, 503, and 504. Use exponential backoff with jitter, starting at 250 ms and doubling, capped at 8 s. Stop after six attempts.
python
import time, random def backoff(attempt): return min(0.25 * 2 ** attempt, 8) * (0.5 + random.random())
Idempotency keys
Pass Idempotency-Key: <uuid> to deduplicate retries. Identical retries within 24 hours return the cached audio bytes; differing bodies under the same key are rejected with 409.