Skip to content
Console

API reference

Voices

Copy page

The voices a key may speak with, and — on voices:write — adding, designing, editing and deleting your own.

When and why to call these: the voices guide.

GET /v1/voices

Every voice this API key may use: the built-in voice, any voices the platform provides, and any your organisation has uploaded. id is what POST /v1/tts takes; name is a label and is not unique. Only a ready voice speaks. One page: next_cursor is always null.

curl
curl "https://api.lumavox.ai/v1/voices" \
-H "Authorization: Bearer $API_KEY"

Responses

Status Description
200 application/json — Every voice available to this key, built-in first
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
422 The request failed validation
429 Rate limit exceeded
503 The voices could not be looked up; the message names the built-in voice, which needs no lookup

200 response body

Field Type Description
data array of VoiceInfo
data[].id string
data[].name string
data[].description string
data[].kind "builtin", "platform", "org" builtin: ships with the platform. platform: added by the platform operator, available to everyone. org: uploaded or designed by your organisation and visible only to it.
data[].status "pending", "ready", "failed" pending: being cloned, and not yet usable for speech. ready: usable. failed: the clone was refused; error says why, and a retry runs it again.
data[].duration_seconds number or null Length of the recording it was cloned from, in seconds; null for a voice not cloned from one.
data[].provider "elevenlabs" Who generates the voice: elevenlabs, whom we speak to on your behalf, billed at that provider’s own rate.
data[].models array of string Which models this voice may be spoken with. Send one of these as model; anything else is refused.
data[].samples array of VoiceSample A spoken sample per model. Always one entry per model, whether or not it has been generated yet. Empty for the built-in voice.
data[].samples[].model string
data[].samples[].ready boolean
data[].samples[].error string or null Why the sample could not be made; null otherwise.
data[].samples[].url string or null Temporary link to the audio, or null when it is not ready. Expires — read it from a fresh response rather than storing it.
data[].created_at string (date-time) or null When it was added; null for the built-in voice.
next_cursor string or null Pass as cursor for the next page; null when this is the last.

POST /v1/voices

Needs voices:write. Counts against your rate limit like a generation.

Creates the voice from a recording uploaded to the URL from POST /v1/voices/upload-url: its upload_id, a name, an optional description, and consent=true confirming you have the right to clone this voice — the upload is refused without it.

The voice comes back with status: pending and cannot be used for speech yet — poll GET /v1/voices/{voice_id} until it is ready, or failed with the reason in error. The recording is cloned by ElevenLabs (instant voice cloning) after this answers, so a recording they refuse arrives as a failed status rather than as a 422.

curl
curl -X POST "https://api.lumavox.ai/v1/voices" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"upload_id":"...","name":"..."}'

Request body (application/json)

FieldTypeRequiredDescription
upload_idstringRequiredFrom the ticket, after the recording was PUT there.
namestringRequiredAt most 120 characters.
descriptionstringAt most 500 characters. Default "".
consentbooleantrue confirms you have the right to clone this voice; the upload is refused without it. Default false.

Responses

Status Description
202 application/json — Accepted. The voice is pending until it is cloned
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
402 Out of credits, or the organisation is suspended — nothing was charged
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
409 No room for another voice (as for the upload URL), the upload never arrived, or it is a voice already
422 The request failed validation
429 Rate limit exceeded
503 Object storage, or the worker, is unavailable

202 response body

Field Type Description
id string
name string
description string
kind "builtin", "platform", "org" builtin: ships with the platform. platform: added by the platform operator, available to everyone. org: uploaded or designed by your organisation and visible only to it.
status "pending", "ready", "failed" pending: being cloned, and not yet usable for speech. ready: usable. failed: the clone was refused; error says why, and a retry runs it again.
error string or null Why a failed voice failed; null otherwise.
source "upload", "design" upload: cloned from a recording. design: kept from the voice designer.
design_prompt string or null What a designed voice was described as; null otherwise.
duration_seconds number or null Length of the recording it was cloned from, in seconds; null for a voice not cloned from one.
samples array of VoiceSample
samples[].model string
samples[].ready boolean
samples[].error string or null Why the sample could not be made; null otherwise.
samples[].url string or null Temporary link to the audio, or null when it is not ready. Expires — read it from a fresh response rather than storing it.
provider "elevenlabs" Who generates the voice: elevenlabs, whom we speak to on your behalf, billed at that provider’s own rate.
external_voice_id string or null The provider’s id for the voice; null until it is cloned.
models array of string
provider_defaults ProviderVoiceSettingsInfo
provider_defaults.stability number or null Low is more expressive and less consistent between generations; high is flatter and more repeatable.
provider_defaults.similarity_boost number or null How closely to cling to the original voice. High can reproduce artefacts in the source.
provider_defaults.style number or null Style exaggeration. Costs latency; leave unset on anything conversational.
provider_defaults.use_speaker_boost boolean or null Similarity at the cost of latency.
provider_defaults.speed number or null 1.0 is the voice’s own pace.
created_at string (date-time)
created_by_clerk_user_id string or null The person who added it, from a screen; null otherwise.
created_by_api_key_id string or null The API key that added it; null otherwise.

POST /v1/voices/upload-url

Needs voices:write. Counts against your rate limit.

A short-lived URL to PUT the recording to, with its type signed in — send exactly that Content-Type and no authentication headers — and the upload_id to create the voice with afterwards (POST /v1/voices). At most the platform’s limits.uploads.voice_bytes (GET /v1/platform/limits). Nothing is created until then.

curl
curl -X POST "https://api.lumavox.ai/v1/voices/upload-url" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"content_type":"audio/mpeg"}'

Request body (application/json)

FieldTypeRequiredDescription
content_typestringRequiredThe recording’s type — audio/wav, audio/mpeg, audio/mp4, audio/ogg, audio/webm… — signed into the URL: the PUT must send exactly this Content-Type.

Responses

Status Description
200 application/json — Where to PUT the recording, and the upload to create the voice from
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
402 Out of credits, or the organisation is suspended — nothing was charged
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
409 The organisation already has as many voices as its plan allows — never more than the platform’s limits.org.voices (GET /v1/platform/limits) — or the provider’s account has no room for another. Delete one, or ask for a higher limit.
422 The request failed validation
429 Rate limit exceeded
503 Object storage is unavailable

200 response body

Field Type Description
upload_id string The voice’s id to be: pass it to the create once the PUT is done.
url string PUT the recording here with the Content-Type below and no authentication headers, before expires_at.
content_type string
expires_at string (date-time) When url stops accepting the recording.

POST /v1/voices/design

Needs voices:write.

Describes a voice in words and gets back several candidates to listen to, as base64 audio. Nothing is saved — keep one with POST /v1/voices/design/save.

Billed per design, whether or not a candidate is kept.

curl
curl -X POST "https://api.lumavox.ai/v1/voices/design" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"...","prompt":"..."}'

Request body (application/json)

FieldTypeRequiredDescription
namestringRequired1–120 characters.
promptstringRequired10–1000 characters.

Responses

Status Description
200 application/json — Candidates to listen to, and the brief they were designed from
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
402 Out of credits, or the organisation is suspended — nothing was charged
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
422 The request failed validation
429 Rate limit exceeded
502 The designer failed; the message says why
503 Voice design or object storage not configured

200 response body

Field Type Description
previews array of VoiceDesignPreview
previews[].id string
previews[].audio_base64 string
previews[].media_type string
previews[].duration_seconds number
previews[].long_enough boolean Whether the preview is long enough to be kept as a voice.
description string The brief the previews were designed from.
script string What the previews say.
improved boolean Whether the description was rewritten into a brief; false when it was used as it came.

POST /v1/voices/design/save

Needs voices:write.

Turns one of the candidates from POST /v1/voices/design into a voice: send back its id as preview_id, a name, and the prompt. Not billed — the design was. The voice is ready at once; its spoken samples follow.

curl
curl -X POST "https://api.lumavox.ai/v1/voices/design/save" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"...","preview_id":"..."}'

Request body (application/json)

FieldTypeRequiredDescription
namestringRequired1–120 characters.
preview_idstringRequiredThe chosen preview’s id, from the design’s answer. 1–64 characters.
descriptionstringAt most 500 characters. Default "".
promptstringAt most 1000 characters. Default "".

Responses

Status Description
202 application/json — Accepted. The voice is ready; its samples follow
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
402 Out of credits, or the organisation is suspended — nothing was charged
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
409 The organisation already has as many voices as its plan allows — never more than the platform’s limits.org.voices (GET /v1/platform/limits) — or the provider’s account has no room for another. Delete one, or ask for a higher limit.
422 The request failed validation
429 Rate limit exceeded
502 The provider could not keep the preview
503 Object storage, or the worker, is unavailable

202 response body

Field Type Description
id string
name string
description string
kind "builtin", "platform", "org" builtin: ships with the platform. platform: added by the platform operator, available to everyone. org: uploaded or designed by your organisation and visible only to it.
status "pending", "ready", "failed" pending: being cloned, and not yet usable for speech. ready: usable. failed: the clone was refused; error says why, and a retry runs it again.
error string or null Why a failed voice failed; null otherwise.
source "upload", "design" upload: cloned from a recording. design: kept from the voice designer.
design_prompt string or null What a designed voice was described as; null otherwise.
duration_seconds number or null Length of the recording it was cloned from, in seconds; null for a voice not cloned from one.
samples array of VoiceSample
samples[].model string
samples[].ready boolean
samples[].error string or null Why the sample could not be made; null otherwise.
samples[].url string or null Temporary link to the audio, or null when it is not ready. Expires — read it from a fresh response rather than storing it.
provider "elevenlabs" Who generates the voice: elevenlabs, whom we speak to on your behalf, billed at that provider’s own rate.
external_voice_id string or null The provider’s id for the voice; null until it is cloned.
models array of string
provider_defaults ProviderVoiceSettingsInfo
provider_defaults.stability number or null Low is more expressive and less consistent between generations; high is flatter and more repeatable.
provider_defaults.similarity_boost number or null How closely to cling to the original voice. High can reproduce artefacts in the source.
provider_defaults.style number or null Style exaggeration. Costs latency; leave unset on anything conversational.
provider_defaults.use_speaker_boost boolean or null Similarity at the cost of latency.
provider_defaults.speed number or null 1.0 is the voice’s own pace.
created_at string (date-time)
created_by_clerk_user_id string or null The person who added it, from a screen; null otherwise.
created_by_api_key_id string or null The API key that added it; null otherwise.

GET /v1/voices/{voice_id}

One of your organisation’s own voices, with its status — pending while the upload is being cloned, failed with the reason in error, ready otherwise. Only voices your organisation owns.

curl
curl "https://api.lumavox.ai/v1/voices/$VOICE_ID" \
-H "Authorization: Bearer $API_KEY"

Path parameters

NameTypeRequiredDescription
voice_idstringRequired

Responses

Status Description
200 application/json — The voice
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
404 Unknown voice
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
id string
name string
description string
kind "builtin", "platform", "org" builtin: ships with the platform. platform: added by the platform operator, available to everyone. org: uploaded or designed by your organisation and visible only to it.
status "pending", "ready", "failed" pending: being cloned, and not yet usable for speech. ready: usable. failed: the clone was refused; error says why, and a retry runs it again.
error string or null Why a failed voice failed; null otherwise.
source "upload", "design" upload: cloned from a recording. design: kept from the voice designer.
design_prompt string or null What a designed voice was described as; null otherwise.
duration_seconds number or null Length of the recording it was cloned from, in seconds; null for a voice not cloned from one.
samples array of VoiceSample
samples[].model string
samples[].ready boolean
samples[].error string or null Why the sample could not be made; null otherwise.
samples[].url string or null Temporary link to the audio, or null when it is not ready. Expires — read it from a fresh response rather than storing it.
provider "elevenlabs" Who generates the voice: elevenlabs, whom we speak to on your behalf, billed at that provider’s own rate.
external_voice_id string or null The provider’s id for the voice; null until it is cloned.
models array of string
provider_defaults ProviderVoiceSettingsInfo
provider_defaults.stability number or null Low is more expressive and less consistent between generations; high is flatter and more repeatable.
provider_defaults.similarity_boost number or null How closely to cling to the original voice. High can reproduce artefacts in the source.
provider_defaults.style number or null Style exaggeration. Costs latency; leave unset on anything conversational.
provider_defaults.use_speaker_boost boolean or null Similarity at the cost of latency.
provider_defaults.speed number or null 1.0 is the voice’s own pace.
created_at string (date-time)
created_by_clerk_user_id string or null The person who added it, from a screen; null otherwise.
created_by_api_key_id string or null The API key that added it; null otherwise.

PATCH /v1/voices/{voice_id}

Needs voices:write.

A partial update: fields you omit are left alone. There is no way to replace the recording — upload a new voice and delete the old one.

curl
curl -X PATCH "https://api.lumavox.ai/v1/voices/$VOICE_ID" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{}'

Path parameters

NameTypeRequiredDescription
voice_idstringRequired

Request body (application/json)

FieldTypeRequiredDescription
namestring1–120 characters.
descriptionstring or nullAt most 500 characters.
modelsarray of stringAt least 1 items.
provider_defaultsProviderVoiceSettings or null
provider_defaults.stabilitynumber or nullLow is more expressive and less consistent between generations; high is flatter and more repeatable. 0–1.
provider_defaults.similarity_boostnumber or nullHow closely to cling to the original voice. High can reproduce artefacts in the source. 0–1.
provider_defaults.stylenumber or nullStyle exaggeration. Costs latency; leave unset on anything conversational. 0–1.
provider_defaults.use_speaker_boostboolean or nullSimilarity at the cost of latency.
provider_defaults.speednumber or null1.0 is the voice’s own pace. 0.7–1.2.

Responses

Status Description
200 application/json — The voice as it now stands
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
404 Unknown voice
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
id string
name string
description string
kind "builtin", "platform", "org" builtin: ships with the platform. platform: added by the platform operator, available to everyone. org: uploaded or designed by your organisation and visible only to it.
status "pending", "ready", "failed" pending: being cloned, and not yet usable for speech. ready: usable. failed: the clone was refused; error says why, and a retry runs it again.
error string or null Why a failed voice failed; null otherwise.
source "upload", "design" upload: cloned from a recording. design: kept from the voice designer.
design_prompt string or null What a designed voice was described as; null otherwise.
duration_seconds number or null Length of the recording it was cloned from, in seconds; null for a voice not cloned from one.
samples array of VoiceSample
samples[].model string
samples[].ready boolean
samples[].error string or null Why the sample could not be made; null otherwise.
samples[].url string or null Temporary link to the audio, or null when it is not ready. Expires — read it from a fresh response rather than storing it.
provider "elevenlabs" Who generates the voice: elevenlabs, whom we speak to on your behalf, billed at that provider’s own rate.
external_voice_id string or null The provider’s id for the voice; null until it is cloned.
models array of string
provider_defaults ProviderVoiceSettingsInfo
provider_defaults.stability number or null Low is more expressive and less consistent between generations; high is flatter and more repeatable.
provider_defaults.similarity_boost number or null How closely to cling to the original voice. High can reproduce artefacts in the source.
provider_defaults.style number or null Style exaggeration. Costs latency; leave unset on anything conversational.
provider_defaults.use_speaker_boost boolean or null Similarity at the cost of latency.
provider_defaults.speed number or null 1.0 is the voice’s own pace.
created_at string (date-time)
created_by_clerk_user_id string or null The person who added it, from a screen; null otherwise.
created_by_api_key_id string or null The API key that added it; null otherwise.

DELETE /v1/voices/{voice_id}

Needs voices:write.

Removes the voice, its samples, and the voice we made for it at the provider. A POST /v1/tts naming the id afterwards is a 404.

curl
curl -X DELETE "https://api.lumavox.ai/v1/voices/$VOICE_ID" \
-H "Authorization: Bearer $API_KEY"

Path parameters

NameTypeRequiredDescription
voice_idstringRequired

Responses

Status Description
204 Deleted
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
404 Unknown voice
422 The request failed validation
429 Rate limit exceeded

POST /v1/voices/{voice_id}/sample

Needs voices:write. Counts against your rate limit like a generation.

A failed voice has its clone run again; a ready one has its spoken samples regenerated; a pending one is already queued and answers 409.

curl
curl -X POST "https://api.lumavox.ai/v1/voices/$VOICE_ID/sample" \
-H "Authorization: Bearer $API_KEY"

Path parameters

NameTypeRequiredDescription
voice_idstringRequired

Responses

Status Description
200 application/json — The voice, pending again where a clone was requeued
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
402 Out of credits, or the organisation is suspended — nothing was charged
403 The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401
404 Unknown voice
409 Still being processed — nothing to retry yet
422 The request failed validation
429 Rate limit exceeded
503 Object storage, or the worker, is unavailable

200 response body

Field Type Description
id string
name string
description string
kind "builtin", "platform", "org" builtin: ships with the platform. platform: added by the platform operator, available to everyone. org: uploaded or designed by your organisation and visible only to it.
status "pending", "ready", "failed" pending: being cloned, and not yet usable for speech. ready: usable. failed: the clone was refused; error says why, and a retry runs it again.
error string or null Why a failed voice failed; null otherwise.
source "upload", "design" upload: cloned from a recording. design: kept from the voice designer.
design_prompt string or null What a designed voice was described as; null otherwise.
duration_seconds number or null Length of the recording it was cloned from, in seconds; null for a voice not cloned from one.
samples array of VoiceSample
samples[].model string
samples[].ready boolean
samples[].error string or null Why the sample could not be made; null otherwise.
samples[].url string or null Temporary link to the audio, or null when it is not ready. Expires — read it from a fresh response rather than storing it.
provider "elevenlabs" Who generates the voice: elevenlabs, whom we speak to on your behalf, billed at that provider’s own rate.
external_voice_id string or null The provider’s id for the voice; null until it is cloned.
models array of string
provider_defaults ProviderVoiceSettingsInfo
provider_defaults.stability number or null Low is more expressive and less consistent between generations; high is flatter and more repeatable.
provider_defaults.similarity_boost number or null How closely to cling to the original voice. High can reproduce artefacts in the source.
provider_defaults.style number or null Style exaggeration. Costs latency; leave unset on anything conversational.
provider_defaults.use_speaker_boost boolean or null Similarity at the cost of latency.
provider_defaults.speed number or null 1.0 is the voice’s own pace.
created_at string (date-time)
created_by_clerk_user_id string or null The person who added it, from a screen; null otherwise.
created_by_api_key_id string or null The API key that added it; null otherwise.