Skip to content
Console

Get started

Errors and limits

Copy page

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:

Response — 422
{
"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.

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.

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
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.wav

An 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.

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:

Response — 429
{
"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.

  • Reads and polls are safe to retry at any time.
  • 429: wait the Retry-After seconds, 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.