Tonedocs

Voices and languages

Twelve Indian languages, and the (model, voice) pairing rule that catches most first-time mistakes.

Read the current options rather than hardcoding them:

curl "$TONE_API/v1/catalog/voice" -H "Authorization: Bearer $TONE_KEY"

πŸ”΄ This catalog is fetched from the speech provider, not hardcoded by us. It changes without a Tone deploy, which is why every list in it is an open set. A voice that is retired is marked deprecated and hidden from pickers, but keeps working for agents already using it β€” a vendor's documentation edit must not break a tenant that changed nothing.

The pairing rule

A voice belongs to a specific model version. The constraint is the (ttsModel, ttsVoice) pair, not the voice name:

{ "ttsModel": "bulbul:v3", "ttsVoice": "simran" }   // ok
{ "ttsModel": "bulbul:v2", "ttsVoice": "simran" }   // 422 β€” simran is a v3 voice

Tone rejects a bad pair when you save the agent, rather than letting you find out mid-call. The request is well-formed, so the answer is a 422 unprocessable_entity, not a 400: the pair is judged against the live catalog. details.path names the field (["ttsVoice"]), and the message lists the voices that model does have. Each speaker in the catalog names the model it belongs to; use that rather than assuming a name carries across versions.

Model-specific tuning is the same trap. bulbul:v2 takes pace, pitch and loudness; v3 dropped the last two and added temperature. An option the model does not take is refused the same way, with details.path naming it.

A voice may speak fewer languages than its model. Every Sarvam voice speaks every catalog language. A voice from another vendor β€” Murf's falcon-2, or Cartesia's sonic-3.6 where it is offered β€” speaks only the codes in its speakers[].languages, and saving an agent with a language its voice cannot speak is the same 422, with details.path pointing at that entry of languages. Cartesia voices also carry a persona.language: the accent the voice was recorded in.

The voice a new agent gets

Leave ttsModel and ttsVoice out when you create an agent and Tone picks one for its languages: a Murf voice (falcon-2) that speaks every language on the list, female like the catalog's default speaker, preferring one native to the first language. When no Murf voice speaks them all, the agent gets the catalog default, bulbul:v3 / simran, which speaks every catalog language. Name a voice yourself and that is what you get.

{ "voice": { "languages": ["hi-IN", "en-IN"] } }   // β†’ falcon-2 / en-IN-pooja
{ "voice": { "languages": ["gu-IN", "en-IN", "hi-IN"] } }   // β†’ bulbul:v3 / simran

Which Murf voices speak which languages changes with the vendor's catalog, so read speakers[].languages from GET /v1/catalog/voice rather than relying on these examples.

Languages

Transcription understands more languages than speech can speak. With auto-detect on, a caller speaking one of the wider set is detected correctly β€” but replying in a language the speech model cannot produce would simply fail.

So a detected language is clamped to the agent's own languages list. Set it to the languages you actually want to handle:

{ "languages": ["hi-IN", "en-IN"] }

An empty list means "no opinion" β€” adopt whatever was detected. That is rarely what you want on a production agent.

Code-switching

Indian callers switch language mid-sentence constantly, and the stack is built for it: detection runs per utterance, not once at the start of the call. An agent with ["hi-IN", "en-IN"] will follow a caller who opens in English and answers in Hindi.

Was this page helpful?

On this page