Get started
Errors and limits
The error envelope, every error code and what to do about it, request ids, rate limits, and retrying safely.
Every error is JSON in one envelope, whatever the endpoint:
{ "error": { "code": "validation_failed", "message": "The request failed validation.", "request_id": "8f3c2a1b9d4e5f60", "issues": [ { "location": "body", "field": "text", "message": "Too small: expected string to have >=1 characters" } ] }}| Field | What it is |
|---|---|
code |
what went wrong, from the table below — switch on this, not on message |
message |
a sentence meant for a person; its wording may change |
request_id |
the request’s id, the same as the X-Request-Id header |
issues |
where a request failed validation, one entry per problem; empty for every other error |
The agent’s WebSocket sends the same code and message in its error frames.
| Status | code |
Means | What to do |
|---|---|---|---|
400 |
invalid_request |
the request could not be read — the body is not valid JSON, or not the form the endpoint takes — or cannot be served as a whole | fix the request; the message says what was wrong |
401 |
unauthenticated |
no credential, or one that is invalid, revoked or expired | check the key |
402 |
insufficient_credits |
your organisation is out of credit, or the balance cannot cover what you asked to set aside or what a queued job’s estimate would charge | see credits and usage |
403 |
forbidden |
the credential is valid but not for this endpoint — usually a missing scope — or your organisation was deleted | use a key with the scope the message names; see authentication |
404 |
not_found |
no such id — or one that belongs to another organisation, which answers the same — or no such path | check the id and the URL |
405 |
method_not_allowed |
the path exists, but not with this method; the Allow header lists the methods it takes |
use one of them |
409 |
conflict |
a plan’s limit on how many agents, voices or end users you hold, an edit to something that changed since you read it, or something still being processed | read the message: delete something, re-read and retry, or wait |
413 |
too_large |
an upload or body over its size limit | see the endpoint’s reference |
415 |
invalid_request |
an upload of a type the endpoint does not read | see the endpoint’s reference |
422 |
validation_failed |
the request does not match the schema, or a value is out of range; issues names each field |
fix the fields issues names |
429 |
rate_limited |
a rate limit — see below | wait Retry-After seconds, then retry |
500 |
internal |
something failed on our side | retry later; report the request_id if it persists |
502 |
provider_failed |
a provider the request depends on failed | retry; report the request_id if it persists |
503 |
unavailable |
something is briefly unreachable, or a capability is not set up on this deployment | retry shortly; the message says which |
A request is authenticated before it is validated: a request with no credential and a bad body is a 401, never a 422. A new code may be added: treat one you do not know by its status.
Validation errors
Section titled “Validation errors”A 422 has one entry in issues per problem:
| Field | What it is |
|---|---|
location |
where the value was: body, query, path or header |
field |
the field, dotted for a nested one (references.0.asset_id); null when the problem is the whole body |
message |
what is wrong with it |
When the schema itself refuses the request, message is The request failed validation. and every problem is in issues. When the endpoint refuses a value it read — an unknown end_user_id, a limit above your plan’s — message says why, and its one issue says where.
A body may only hold the fields its endpoint knows: an unknown one is an issue of its own, naming it.
Request ids
Section titled “Request ids”Every response — success or error — carries an X-Request-Id header, and every error repeats it as request_id. Quote it when you report a problem: it finds your request in our logs.
You can send your own:
curl https://api.lumavox.ai/v1/tts \ -H "Authorization: Bearer $API_KEY" \ -H "X-Request-Id: order-1234-greeting" \ -H "Content-Type: application/json" \ -d '{"text": "Your order is on its way."}' \ --output greeting.wavAn id of 1 to 64 letters, digits, ., _ and -, starting with a letter or digit, is used as given. Anything else is replaced with a fresh id rather than refused.
Rate limits
Section titled “Rate limits”Limits belong to your organisation’s plan and are shared by every key in it. They count the requests that spend — speech, transcription, generation submits, uploads, voice design, knowledge writes. Reads and polls are not counted.
A plan can limit:
- requests a minute and requests an hour;
- requests running at the same time — the ones that keep working while you wait: speech and transcription (
/v1/tts,/v1/stt), uploading a voice, designing one and keeping a design, and confirming an upload. A queued submit answers at once, so it holds nothing; - each of those again for one capability — speech, images, transcription and so on — on top of the organisation-wide ones.
Over any of them, the request answers 429 with a Retry-After header in seconds. Nothing has been charged. The message says which limit it was:
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded: more than 300 requests per minute.", "request_id": "8f3c2a1b9d4e5f60", "issues": [] }}When your plan sets no window a minute, the platform’s own applies. Some capabilities have limits of their own, also answered with 429: how many of your generations may be unfinished at once, and how many ephemeral keys you mint a minute. Plans also cap how many agents, voices and end users you hold; past those, creating another is a 409. The platform’s limits, as its staff set them, are listed on Limits.
Retrying safely
Section titled “Retrying safely”- Reads and polls are safe to retry at any time.
429: wait theRetry-Afterseconds, then retry.500,502,503: retry with an increasing delay — a second, then a few, then longer.- Everything else in the 4xx range will fail the same way again. Fix the request first.
The API has no idempotency keys: a retried POST is a new request. If a submit to a queued endpoint timed out on your side, it may have been accepted — and charged — anyway. Before you send it again, look for it with GET /v1/generations?status=queued (or running); see queued jobs. The one create that is safe to repeat is POST /v1/end-users with your own external_id, which returns the same end user every time.
Related
Section titled “Related”- Conventions — how times, credits and lists are written.
- Authentication — keys, scopes, 401 and 403.
- Credits and usage — the balance, and what 402 means.
- Queued jobs — reconciling submits after a failure.