Errors & Limits
Error codes, retries, rate limits and idempotency keys.
Error responses
{
"code": -1,
"message": "Voice not found",
"data": {
"error_code": "NOT_FOUND",
"retryable": false,
"request_id": "0b5e2f1a-…",
"voice_id": "…"
}
}
error_code- a stable code; handle errors based on it.retryable- whentrue, retry the same request later (with exponential backoff); whenfalse, change the request or your account first.request_id- the ID of this request, also in theX-Request-Idresponse header. Include it when contacting support.- Other fields add detail, such as
field(the invalid parameter),index(the failing batch item), orrequired/available(credits needed and available).
Error codes
| HTTP | error_code | Retryable | Meaning and what to do |
|---|---|---|---|
| 400 | INVALID_REQUEST | No | Missing or invalid parameter - see field |
| 400 | CONSENT_REQUIRED | No | consent=true was not sent when cloning a voice |
| 400 | SAMPLE_QUALITY_FAILED | No | The clone sample failed the quality check - see issues |
| 400 | CONTENT_REJECTED | No | The input was rejected by content moderation |
| 401 | UNAUTHORIZED | No | Missing, invalid or deleted API key |
| 402 | INSUFFICIENT_CREDITS | No | Not enough credits - see required and available; buy credits and retry |
| 403 | API_ACCESS_REQUIRED | No | Your plan doesn't include the API - upgrade to Standard or above |
| 403 | UPGRADE_REQUIRED | No | A plan limit was exceeded (characters, file size, duration) - see max_allowed and similar fields |
| 403 | VOICE_LIMIT_REACHED | No | No voice slots left - delete unused voices or upgrade |
| 404 | NOT_FOUND | No | The resource doesn't exist or isn't yours |
| 409 | VOICE_NOT_READY | No | The voice isn't usable yet (voice_status shows its state) |
| 409 | IDEMPOTENCY_KEY_REUSED | No | The idempotency key was used for a different request |
| 409 | IDEMPOTENCY_IN_PROGRESS | Yes | An earlier request with the same idempotency key is still running |
| 413 | FILE_TOO_LARGE | No | The uploaded file is larger than 30MB |
| 415 | UNSUPPORTED_AUDIO_FORMAT | No | Only WAV, MP3, OGG, WEBM and M4A are supported |
| 429 | RATE_LIMITED | Yes | Too many requests - wait Retry-After seconds and retry |
| 500 | INTERNAL_ERROR | Yes | Internal error - retry later |
| 503 | SYSTEM_BUSY | Yes | The system is busy - retry later |
When the task itself fails (rather than the create request), the task's error.code is SYNTHESIS_FAILED. Charged credits are refunded automatically and you can create the task again.
Rate limits
Limits are per account and shared by all of its keys:
| Plan | Requests per minute |
|---|---|
| Standard | 60 |
| Premium | 120 |
Every response includes these headers:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests left in the current window |
X-RateLimit-Reset | When the window resets (Unix seconds) |
Retry-After | Seconds to wait when rate limited |
The number of tasks generating at the same time is also capped by plan (Standard 5, Premium 10). Extra tasks are queued automatically - they don't fail.
Contact [email protected] if you need higher limits.
Other limits
| Item | Limit |
|---|---|
| Characters per text-to-speech task | By plan - 1,000 on Standard and above |
| Items per batch | 100 |
| Upload size | 30MB, and within your plan's limit |
| Voice conversion duration | 5 minutes |
| Items per list page | 100 (50 for public voices) |
GET /account returns the exact values for your plan in limits.
Idempotency keys
Retrying a create request after a network timeout could create a duplicate task and charge you twice. Add an Idempotency-Key header to every create request (POST /tts, POST /tts/batches, POST /voice-conversion, POST /voices) to prevent that:
curl https://voiceailabs.com/api/v1/tts \
-H "Authorization: Bearer $VAL_API_KEY" \
-H "Idempotency-Key: 4f9a1c2e-order-1024" \
-H "Content-Type: application/json" \
-d '{"voice_id": "VOICE_ID", "text": "Hello"}'
- A key is 1–255 visible ASCII characters. Use a UUID or a business ID from your system.
- For 24 hours, sending the same request with the same key returns the original result (with the
Idempotent-Replayed: trueheader) without creating or charging again. - Using the same key for a different request returns
IDEMPOTENCY_KEY_REUSED. - Only successful requests are recorded. If a request fails (for example, insufficient credits), fix it and retry with the same key.
- If you keep getting
IDEMPOTENCY_IN_PROGRESSfor more than a minute, checkGET /synthesesto see whether the task was created before retrying with a new key.