Skip to main content

Response envelope

Every response uses a consistent envelope. Success:
{ "success": true, "data": { /* ... */ } }
Failuresuccess: false, data: null, and an error object with a machine-readable code:
{ "success": false, "data": null, "error": { "code": "UNAUTHORIZED" } }
Always branch on the HTTP status first, then read error.code for specifics.

Common HTTP statuses

StatusMeaningWhat to do
400Malformed requestFix the request body/parameters.
401Missing/invalid API keyCheck the X-API-Key / Authorization header.
402Out of creditsYou’ve used your cycle’s credits — see Rate limits & quota.
413Payload too largeShorten text, or reduce the ASR audio file.
415Unsupported mediaUse a supported audio format (see ASR).
422Validation errorA field failed validation (e.g. text length).
429Too many requestsBack off and retry — see Rate limits.
5xxServer errorTransient; retry with backoff.

Handling errors

Python
resp = requests.post(url, headers=headers, json=payload)

if resp.status_code == 429:
    # rate limited — wait and retry
    ...
elif not resp.ok:
    body = resp.json()
    code = (body.get("error") or {}).get("code")
    raise RuntimeError(f"{resp.status_code} {code}")
Streaming endpoints (/v1/speech/synthesize) signal failures with a non-200 status before the stream starts. Once a 200 NDJSON stream begins, check for an error record/early close if the connection drops mid-stream.

Retries

Retry 429 and 5xx with exponential backoff (e.g. 1s, 2s, 4s) and a cap. Do not retry 4xx other than 429 — fix the request instead.