Reference
Voices
GET /v1/voices: every voice your org can speak with at a provider, your account's own included, in one shape.
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"curl "https://api.ttscacherouter.dev/v1/voices?provider=deepgram&model=flux" \ -H "Authorization: Bearer $TTS_CACHE_ROUTER_API_KEY"providerstringRequiredsarvam,raya,elevenlabs,openai,deepgram,xaiorsoniox.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.
{ "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
voicetakes on/v1/stream,/v1/audio/speechand the LiveKit plugin. A Deepgram voice is its model id without the model:thalia-enwithaura-2is Deepgram’saura-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 | nullmale,femaleorneutral, 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_languagesandhigh_quality_base_model_ids, Deepgram’stagsandimage, Soniox’suse_caseandstyle. 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.
| provider | Voices from | Categories | Previews |
|---|---|---|---|
| sarvam | The router's catalog: bulbul:v3's 37 speakers (with gender) and bulbul:v4-flash's personas | builtin | No |
| raya | Raya's voice list; each voice belongs to one model | builtin | No |
| elevenlabs | Your ElevenLabs account's voices, every page | builtin, cloned, custom, library | Yes |
| openai | The router's catalog | builtin | No |
| deepgram | Deepgram's model lists: Aura and Aura-2, and Flux | builtin | Yes |
| xai | xAI's voices and your custom voices | builtin, cloned | No |
| soniox | Soniox's voices and your project's cloned voices | builtin, cloned | No |
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.
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"}'curl "https://api.ttscacherouter.dev/elevenlabs/v1/voices/JBFqnCBsd6RMkjVDRZzb/settings" \ -H "xi-api-key: $TTS_CACHE_ROUTER_API_KEY"{"stability": 0.5, "use_speaker_boost": true, "similarity_boost": 0.75, "style": 0.0, "speed": 1.0}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.