Reference

Voices

GET /v1/voices: every voice your org can speak with at a provider, your account's own included, in one shape.

View as Markdown

Request#

GET https://api.ttscacherouter.dev/v1/voices with your router API key as Authorization: Bearer tcr_…. It lists the voices your org can speak with at one provider, your provider account’s own included, read live with the provider key stored under Provider keys.

curl "https://api.ttscacherouter.dev/v1/voices?provider=elevenlabs" \  -H "Authorization: Bearer $TTS_CACHE_ROUTER_API_KEY"
providerstringRequired
sarvam, raya, elevenlabs, openai, deepgram, xai or soniox.
modelstringOptional
Only the voices this model takes, by the router’s model id without the provider (bulbul:v4-flash, aura-2, m1). See Models and options.

The answer is the whole list: where a provider pages its list, the router reads every page. Nothing is cached, so a voice you add at the provider is listed on your next request. Only voices the router can speak with are listed.

Response#

One shape for every provider. Each voice's id is what voice takes, with any of its models, on every surface.

JSON
{  "voices": [    {      "id": "JBFqnCBsd6RMkjVDRZzb",      "name": "George - Warm, Captivating Storyteller",      "provider": "elevenlabs",      "models": ["eleven_flash_v2_5", "eleven_turbo_v2_5", "eleven_multilingual_v2", "…"],      "languages": ["en", "es", "fr"],      "gender": "male",      "accent": "british",      "age": "middle_aged",      "description": "Warm resonance that instantly captivates listeners.",      "preview_url": "https://storage.googleapis.com/eleven-public-prod/…/preview.mp3",      "category": "builtin",      "provider_data": {"voice_id": "JBFqnCBsd6RMkjVDRZzb", "category": "premade", "labels": {"…": "…"}, "…": "…"}    }  ]}
idstring
What voice takes on /v1/stream, /v1/audio/speech and the LiveKit plugin. A Deepgram voice is its model id without the model: thalia-en with aura-2 is Deepgram’s aura-2-thalia-en.
namestring
The provider's display name.
providerstring
The provider asked for.
modelsstring[]
The router's model ids the voice works with. Every ElevenLabs voice works with every ElevenLabs model.
languagesstring[]
The languages the voice is made for, in the provider’s codes. A voice that speaks every language of its model lists them all (Sarvam’s bulbul:v3, OpenAI, xAI’s built-in voices, Soniox); an ElevenLabs voice lists its own language, then those ElevenLabs verified it in; a bulbul:v4-flash persona the one it was recorded in. Empty when the provider doesn’t say.
genderstring | null
male, female or neutral, where the provider says.
accentstring | null
In the provider's own words, where it says.
agestring | null
In the provider's own words, where it says.
descriptionstring | null
The provider's description of the voice, where it has one.
preview_urlstring | null
A sample of the voice at the provider's own URL, where it has one (ElevenLabs, Deepgram). Play it straight from there: it needs no key.
categorystring
Where the voice comes from: see Categories.
provider_dataobject | null
The provider’s own voice object, as it came: ElevenLabs’ labels, verified_languages and high_quality_base_model_ids, Deepgram’s tags and image, Soniox’s use_case and style. Null for voices from the router’s catalog (Sarvam, OpenAI), which no provider API lists.

Categories#

Where each provider's voices come from, and the categories they can have.

builtin
The provider's own stock voices.
cloned
Cloned in your provider account from recordings: ElevenLabs instant and professional clones, xAI custom voices, Soniox cloned voices (once ready).
custom
Made in your provider account another way: ElevenLabs voice design.
library
Added to your provider account from the provider's shared library: ElevenLabs.
providerVoices fromCategoriesPreviews
sarvamThe router's catalog: bulbul:v3's 37 speakers (with gender) and bulbul:v4-flash's personasbuiltinNo
rayaRaya's voice list; each voice belongs to one modelbuiltinNo
elevenlabsYour ElevenLabs account's voices, every pagebuiltin, cloned, custom, libraryYes
openaiThe router's catalogbuiltinNo
deepgramDeepgram's model lists: Aura and Aura-2, and FluxbuiltinYes
xaixAI's voices and your custom voicesbuiltin, clonedNo
sonioxSoniox's voices and your project's cloned voicesbuiltin, clonedNo

Sarvam’s cloned voices aren’t listed: Sarvam speaks them only through its voice-cloning API, not its Bulbul models. OpenAI lists no custom voices, and the router passes voice as a name.

Speaking with a voice#

Pass the voice's id as voice, with one of its models, on any surface.

agent.py
from livekit.plugins import tts_cache_router as tcr# A voice from GET /v1/voices?provider=deepgram&model=aura-2tts = tcr.TTS(model="deepgram/aura-2", voice="thalia-en")

See TTS(model=...) for the plugin, and /v1/audio/speech over HTTP.

Library voices and voice settings#

ElevenLabs' library and voice settings are on the ElevenLabs drop-in, with your router API key in xi-api-key.

# Browse ElevenLabs' voice librarycurl "https://api.ttscacherouter.dev/elevenlabs/v1/shared-voices?page_size=10&language=hi" \  -H "xi-api-key: $TTS_CACHE_ROUTER_API_KEY"# Add one to your ElevenLabs account: its public_owner_id and voice_idcurl -X POST "https://api.ttscacherouter.dev/elevenlabs/v1/voices/add/$PUBLIC_OWNER_ID/$VOICE_ID" \  -H "xi-api-key: $TTS_CACHE_ROUTER_API_KEY" \  -H "Content-Type: application/json" \  -d '{"new_name": "Support voice"}'

A voice you add appears in GET /v1/voices?provider=elevenlabs as library. A voice’s settings are what a request without voice_settings uses. Each provider’s own voice endpoints are on its drop-in page: ElevenLabs, Raya, Deepgram, xAI and Soniox.

Errors#

The router's error body, with its HTTP status. A provider's refusal passes through: its status in provider_status, its body in message.

HTTP/1.1 400 Bad Request{"error": {"code": "provider_rejected",           "message": "xAI answered HTTP 400: {\"code\":\"Client specified an invalid argument\",\"error\":\"Incorrect API key provided. You can obtain an API key from https://console.x.ai.\"}",           "retryable": false, "provider_status": 400}}
bad_requestHTTP 400, not retryable
The request failed validation or a message arrived out of order. The message says which field or rule.
unauthorizedHTTP 401, not retryable
The API key is missing, wrong or deleted, or its org is disabled.
insufficient_creditsHTTP 402, not retryable
Your org is out of credit, so the router refuses new connections and requests until you buy more. Connections already open carry on.
provider_key_missingHTTP 400, not retryable
Your org has no key stored for the provider. Add one under Provider keys.
provider_rejectedHTTP 400, not retryable
The provider refused the request, e.g. a wrong stored provider key or an unknown voice. The provider’s message is passed through.
provider_rate_limitedHTTP 429, retryable
Your own quota at the provider is exhausted.
provider_unavailableHTTP 502, retryable
The provider returned a server error, or the connection to it failed or closed unexpectedly.
provider_timeoutHTTP 504, retryable
The provider took too long to send audio.
internalHTTP 500, retryable
The router failed.

A missing or unknown provider or model, or any other query parameter, is a bad_request. An org with no key stored for the provider gets provider_key_missing, also for Sarvam and OpenAI, whose voices come from the router’s catalog. Deepgram’s model lists are public, so a wrong Deepgram key still lists its voices; it is refused when you speak.