Per-call settings reference
This chapter lists every value you can set for one call: speech provider, voice, model, recogniser, language, bot and realtime mode. It then shows how to set them on inbound calls, either with SIP headers or from an Asterisk dialplan. Outbound calls take the same keys in the request body; see Outbound SIP calls and per-call settings.
Anything you do not set for a call comes from .env.
The keys
| Setting | Metadata key (POST, outbound) | Inbound SIP header | Honoured by |
|---|---|---|---|
| Speech provider | tts_provider |
X-TTS-Provider |
Every call |
| Voice | tts_voice |
X-TTS-Voice |
sarvam, google, gemini, smallest, openrouter |
| Speech model | tts_model |
X-TTS-Model |
gemini, openrouter |
| Recogniser | stt_provider |
X-STT-Provider |
Every call |
| Language | language_code |
X-Language |
Every call |
| Bot | botId |
X-Bot-Id |
LiteBot brain, LiteBot Live, Gemini Live |
| Realtime mode | realtimeProvider |
X-Realtime-Provider |
Every call |
Header names are not case-sensitive. A header value that fails the check is dropped with a warning (for example Invalid x-tts-provider "polly" in SIP call <id>, ignoring) and the .env default applies. The same checks run on the metadata POST and the outbound request, so a value accepted in one place is accepted in all.
tts_voice and tts_model are read only by the provider named in tts_provider for that call (or the .env provider when you set none). If the voice id does not belong to that provider, the provider rejects it and that sentence goes to the fallback provider. For the providers that do not take a per-call voice (elevenlabs, deepgram, azure, murf, vexyl), pick the voice per language in .env instead: ELEVENLABS_VOICE_<LANG>, DEEPGRAM_VOICE_<LANG>, AZURE_TTS_VOICE_<LANG>, MURF_VOICE_<LANG>, VEXYL_TTS_SPEAKER_<LANG>.
tts_provider
| Value | Per-call voice | Per-call model | Notes |
|---|---|---|---|
sarvam |
yes | no (model is SARVAM_TTS_MODEL) |
Indian languages; voice ids differ between bulbul:v3 and bulbul:v4-flash |
google |
yes | no | Chirp3-HD voices; the voice name also sets the language |
gemini |
yes | yes | Prebuilt voices or your own designed voice |
smallest |
yes | no | Indian languages incl. Malayalam, native 8 kHz |
openrouter |
yes | yes | Many vendors behind one key; voice ids depend on the model |
elevenlabs |
no | no | Voice per language in .env |
deepgram |
no | no | Voice per language in .env |
azure |
no | no | Voice per language in .env |
murf |
no | no | Voice per language in .env |
vexyl |
no | no | Self-hosted; speaker per language in .env |
Provider set-up and keys are in Text to speech.
tts_voice by provider
sarvam
The voice id depends on the model in SARVAM_TTS_MODEL:
- bulbul:v3 (the default model) takes a bare speaker name, for example
kavya(the default),shubh,aditya,ritu,amit. - bulbul:v4-flash takes a persona id
<name>_<lang>_<style>, for examplekavya_hi_conversational(the default),aparna_hi_kyc,shilpa_hi_narration.
The gateway converts between the two forms: a bare name on v4-flash becomes that speaker's persona, and a persona on v3 becomes its bare name, with one warning in the log. The language of the call comes from language_code, not from the persona tag, so a Hindi-tagged persona speaks Malayalam correctly on an ml-IN call. There is no Malayalam or Odia persona; use a _hi_ or _enhi_ one.
The bulbul:v4-flash personas built into this release (a name Sarvam adds later is passed through unchanged and Sarvam decides):
Assamese (`_as_`, 2):
kangkana_as_conversational mouchumi_as_conversational
Bengali (`_bn_`, 3):
arnab_bn_conversation roopa_bn_conversational bimal_bn_suspense
English (`_en_`, 62):
aditi_en_stories aparna_en_companion aparna_en_edtech ashwin_en_sports
ashwin_en_sports_energetic chandrika_en_stories dev_en_recovery dev_en_conversational
deven_en_conversation ishita_en_customer ishita_en_medical ishita_en_numbers ishita_en_social
ishita_en_stories kalpit_en_edtech nachiket_en_ads neha_en_customer neha_en_latenight
nupur_en_kids ojas_en_social ritu_en_edtech ritu_en_latenight ritu_en_medical ritu_en_reels
rohan_en_recovery roopa_en_conversational rustom_en_suspense sanchita_en_companion
sanchita_en_insurance sanchita_en_recovery sanchita_en_market sanchita_en_social
shabana_en_edtech shalini_en_companion shalini_en_customer shubh_en_narration shubh_en_numbers
shubh_en_ads shubh_en_recovery shubh_en_audiobook shubh_en_narration_gentle shubh_en_sports
simran_en_narration simran_en_automobile simran_en_conversation simran_en_customer
simran_en_edtech simran_en_edtech_bot simran_en_sales simran_en_recovery simran_en_ads
simran_en_therapist sunny_en_social varun_en_ads varun_en_suspense zarina_en_conversation
amelia_en_conversational sophia_en_conversational girish_en_documentary girish_en_devotional
payal_en_edtech sarang_en_narration
Hinglish (`_enhi_`, 13):
ishita_enhi_companion ishita_enhi_customer ishita_enhi_customer_expressive
sanchita_enhi_companion shalini_enhi_companion shalini_enhi_customer shubh_enhi_companion
shubh_enhi_ads shubh_enhi_banking simran_enhi_companion simran_enhi_customer
simran_enhi_banking_expressive sunny_enhi_customer
Gujarati (`_gu_`, 3):
bhavik_gu_conversation pooja_gu_conversational pooja_gu_customer
Hindi (`_hi_`, 116):
aayan_hi_conversational amit_hi_conversational ashutosh_hi_conversational
kabir_hi_conversational kavya_hi_conversational manan_hi_conversational
rahul_hi_conversational sumit_hi_conversational aditya_hi_conversational aditya_hi_sales
anand_hi_documentary anand_hi_news aparna_hi_customer aparna_hi_kyc ashok_hi_character
ashok_hi_news chhavi_hi_kids ishita_hi_ads ishita_hi_edtech ishita_hi_banking
ishita_hi_ads_informal ishita_hi_devotional ishita_hi_numbers ishita_hi_social kunal_hi_kids
mahesh_hi_documentary mani_hi_devotional mani_hi_conversational mohit_hi_conversational
nachiket_hi_devotional priya_hi_recovery ratan_hi_latenight ratan_hi_customer_expressive
ratan_hi_documentary ratan_hi_devotional ratan_hi_recovery ratan_hi_social ratan_hi_sports
ratan_hi_latenight_warm rehan_hi_social ritu_hi_customer_utility ritu_hi_kids
ritu_hi_conversation ritu_hi_customer ritu_hi_edtech ritu_hi_ads_formal ritu_hi_banking
ritu_hi_ads_informal ritu_hi_insurance ritu_hi_edtech_bot ritu_hi_medical ritu_hi_sales
ritu_hi_reels ritu_hi_social ritu_hi_customer_warm ritu_hi_social_lively roopa_hi_companion
roopa_hi_narration roopa_hi_recovery roopa_hi_market roopa_hi_conversational
sanchita_hi_assistant sanchita_hi_edtech sanchita_hi_banking sanchita_hi_feedback
sanchita_hi_ads_formal sanchita_hi_ads_informal sanchita_hi_interview sanchita_hi_romantic
sanchita_hi_market sanchita_hi_social sanchita_hi_kyc sarika_hi_conversation
shalini_hi_companion shalini_hi_social shreya_hi_conversational shreya_hi_news
shruti_hi_edtech shubh_hi_customer shubh_hi_ecomm shubh_hi_stories_mixed shubh_hi_devotional
shubh_hi_ads shubh_hi_recovery shubh_hi_stories_dramatic simran_hi_assistant
simran_hi_narration simran_hi_automobile simran_hi_conversation simran_hi_news_breaking
simran_hi_social_energetic simran_hi_social_excited simran_hi_latenight simran_hi_news
simran_hi_recovery simran_hi_sales suchitra_hi_ecomm suhani_hi_social sunny_hi_ads
sunny_hi_reels tarun_hi_conversational tarun_hi_sales chaitra_hi_customer shilpa_hi_narration
tanya_hi_narration aarti_hi_customer advait_hi_character aryaman_hi_ads chirag_hi_social
girish_hi_devotional mukul_hi_ads mukul_hi_suspense suman_hi_companion vaibhav_hi_social
vandana_hi_ecomm vipul_hi_social
Kannada (`_kn_`, 4):
chaitra_kn_conversation chaitra_kn_narration chetan_kn_conversation suchitra_kn_narration
Marathi (`_mr_`, 9):
ishita_mr_conversational mrunal_mr_narration neha_mr_narration nilesh_mr_conversation
ritu_mr_insurance ritu_mr_narration rupali_mr_stories soham_mr_narration mukul_mr_stories
Punjabi (`_pa_`, 4):
anand_pa_conversation anand_pa_customer harpreet_pa_narration jaspal_pa_banking
Tamil (`_ta_`, 4):
gokul_ta_narration aravind_ta_ads aravind_ta_suspense vijay_ta_narration
Telugu (`_te_`, 4):
kavitha_te_conversation kavitha_te_narration pooja_te_conversation tarun_te_narration
A Chirp3-HD voice: <locale>-Chirp3-HD-<Name>, for example ml-IN-Chirp3-HD-Despina. Keep Chirp3-HD voices: other types do not stream, so replies start later. The locale must match the call language, otherwise Google rejects the request. Three locales differ from the call language: zh-CN uses cmn-CN, ar-AE uses ar-XA, and or-IN has no Google voice at all (an Odia call on google fails over to another provider).
The 30 names:
| Female | Male |
|---|---|
| Achernar (default), Aoede, Autonoe, Callirrhoe, Despina, Erinome, Gacrux, Kore, Laomedeia, Leda, Pulcherrima, Sulafat, Vindemiatrix, Zephyr | Achird, Algenib, Algieba, Alnilam, Charon, Enceladus, Fenrir, Iapetus, Orus, Puck, Rasalgethi, Sadachbia, Sadaltager, Schedar, Umbriel, Zubenelgenubi |
gemini
One of the same 30 names, without a locale: Kore, Puck, Charon and so on. Or the id of a voice you designed or replicated, voice_<uuid>; such a call always goes through Vertex AI. See Custom voices.
smallest
A voice id from the Smallest voice library, for example avni (the default), or a cloned voice id voice_…. Most library voices speak all the Indian languages Smallest supports. Avoid divya: it cuts long sentences short.
openrouter
Voice ids belong to the model:
tts_model |
Example tts_voice |
|---|---|
mistralai/voxtral-mini-tts-3-0 (the default) |
voice_3150 |
google/gemini-3.8-flash-tts, google/gemini-3.8-flash-lite-tts |
Kore, Puck (the 30 names above) |
hexgrad/kokoro-82m, x-ai/grok-voice-tts-1.0, elevenlabs/eleven-flash-v2.5, deepgram/aura-2 |
That vendor's voice id |
tts_model
| Provider | Values |
|---|---|
gemini |
gemini-2.5-flash-tts, gemini-2.5-pro-tts, gemini-3.8-flash-tts, gemini-3.8-flash-lite-tts. The 3.8 models run on Vertex AI and stream. Unset means GEMINI_TTS_MODEL. |
openrouter |
vendor/name, for example mistralai/voxtral-mini-tts-3-0 (default), google/gemini-3.8-flash-lite-tts, google/gemini-3.8-flash-tts, hexgrad/kokoro-82m, x-ai/grok-voice-tts-1.0, elevenlabs/eleven-flash-v2.5, deepgram/aura-2 |
A model id is letters, digits and _ . -, with one optional /. A voice id is up to 160 letters, digits and _ . : -. Anything else is dropped.
stt_provider
| Value | Mode | Languages |
|---|---|---|
sarvam |
Streaming | The 11 Indian languages below |
sarvam-r |
Batch | The 11 Indian languages below |
google |
Streaming | All 22 languages below |
vexyl-stt |
Streaming, self-hosted | The 11 Indian languages below |
deepgram |
Batch | Deepgram's own language list |
groq |
Batch | All 22 languages below |
gemini |
Batch | All 22 languages below |
openai |
Batch | OpenAI's own language list |
A per-call recogniser is used as given, even if it does not know the call language, so match the two. With no stt_provider and STT_PROVIDER=auto, Indian languages go to Sarvam and the rest to Groq. Models and tuning for each are in Speech recognition.
language_code
| Indian (Sarvam, Google, Groq, Gemini, Vexyl) | Other (Google, Groq, Gemini) |
|---|---|
ml-IN Malayalam, en-IN English, hi-IN Hindi, ta-IN Tamil, te-IN Telugu, kn-IN Kannada, mr-IN Marathi, gu-IN Gujarati, or-IN Odia, pa-IN Punjabi, bn-IN Bengali |
en-US English (US), es-ES Spanish, fr-FR French, de-DE German, ar-XA Arabic, ar-AE Arabic (UAE), zh-CN Chinese (Mandarin), ja-JP Japanese, ko-KR Korean, ru-RU Russian, pt-BR Portuguese (Brazil) |
The header form is the same code; en-us is accepted and stored as en-US.
botId and realtimeProvider
botId: the id of a bot. With the LiteBot brain it is the LiteBot bot id; an unknown id falls back to the default bot. In a header, an id is letters, digits and_ . -, up to 64 characters.realtimeProvider:litebotorgemini-livefor speech-to-speech,offorpipelinefor the standard pipeline. See Realtime mode.
Inbound: set them with SIP headers
Any PBX that sends INVITEs to the gateway's SIP bridge can add these headers. Nothing else is needed: no HTTP request, no session id. On the gateway, the call log then shows:
INFO: SIP header overrides for <session-id>: {"tts_provider":"sarvam","tts_voice":"shilpa_hi_narration","language_code":"ml-IN","botId":"support"}
The dialled number is stored with the call as destination_number whether or not you send headers.
Asterisk or FreePBX (chan_pjsip)
Headers must be added in a pre-dial handler, so they land on the outgoing INVITE:
[to-vexyl-bot]
exten => _X.,1,NoOp(To the bot)
same => n,Dial(PJSIP/${EXTEN}@vexyl-gw,60,b(vexyl-settings^s^1(support,ml-IN,sarvam,shilpa_hi_narration,sarvam)))
same => n,Hangup()
[vexyl-settings]
; ARG1 bot, ARG2 language, ARG3 TTS provider, ARG4 voice, ARG5 recogniser
exten => s,1,Set(PJSIP_HEADER(add,X-Bot-Id)=${ARG1})
same => n,Set(PJSIP_HEADER(add,X-Language)=${ARG2})
same => n,Set(PJSIP_HEADER(add,X-TTS-Provider)=${ARG3})
same => n,Set(PJSIP_HEADER(add,X-TTS-Voice)=${ARG4})
same => n,Set(PJSIP_HEADER(add,X-STT-Provider)=${ARG5})
same => n,Return()
Different settings per number:
[to-vexyl-bot]
exten => 5550101,1,Dial(PJSIP/${EXTEN}@vexyl-gw,60,b(vexyl-settings^s^1(sales,en-IN,google,en-IN-Chirp3-HD-Kore,google)))
exten => 5550102,1,Dial(PJSIP/${EXTEN}@vexyl-gw,60,b(vexyl-settings^s^1(support,hi-IN,sarvam,aparna_hi_kyc,sarvam)))
On the older chan_sip driver, use SIPAddHeader(X-Bot-Id: support) (one per header) before Dial() instead of the pre-dial handler.
For a model as well, add Set(PJSIP_HEADER(add,X-TTS-Model)=gemini-3.8-flash-lite-tts) with X-TTS-Provider set to gemini.
Other PBXs
Look for a trunk setting named custom SIP headers, extra headers or header manipulation, and add the headers there, for example X-Bot-Id: support and X-Language: ml-IN. A trunk-level header applies to every call on that trunk, so use one trunk per bot profile if the PBX cannot set headers per route. Vendor menus are in Connecting Panasonic, Avaya, Grandstream and Bitvoice PBXs.
Headers together with X-Session-UUID
If the INVITE also carries X-Session-UUID and you posted metadata under that id, the posted values win. A header only fills a key the POST did not set. Use one method per key to keep it simple.
Inbound: set them from the Asterisk dialplan (AudioSocket)
With AudioSocket there is no SIP leg to the gateway, so post the keys before AudioSocket():
[voice-assistant]
exten => _X.,1,Answer()
same => n,Set(SESSION_UUID=${TRIM(${SHELL(uuidgen)})})
same => n,Set(META=caller_id=${URIENCODE(${CALLERID(num)})}&channel=${URIENCODE(${CHANNEL})}&destination_number=${EXTEN}&botId=support&language_code=ml-IN&tts_provider=sarvam&tts_voice=shilpa_hi_narration&stt_provider=sarvam)
same => n,Set(CURL_RESULT=${CURL(http://127.0.0.1:8081/session/${SESSION_UUID}/metadata,${META})})
same => n,AudioSocket(${SESSION_UUID},127.0.0.1:8080)
same => n,Hangup()
A caller-chosen language and per-number settings from the Asterisk database are shown in Dialplan: choose settings from the call.
Settings sent by an upstream PBX
When a customer PBX sends the headers above to your Asterisk, and Asterisk connects the call over AudioSocket, read the headers and post them:
[from-customer-pbx]
exten => _X.,1,Answer()
same => n,Set(SESSION_UUID=${TRIM(${SHELL(uuidgen)})})
same => n,Set(VX_BOT=${PJSIP_HEADER(read,X-Bot-Id)})
same => n,Set(VX_LANG=${PJSIP_HEADER(read,X-Language)})
same => n,Set(VX_TTS=${PJSIP_HEADER(read,X-TTS-Provider)})
same => n,Set(VX_VOICE=${PJSIP_HEADER(read,X-TTS-Voice)})
same => n,Set(VX_STT=${PJSIP_HEADER(read,X-STT-Provider)})
same => n,Set(META=caller_id=${URIENCODE(${CALLERID(num)})}&channel=${URIENCODE(${CHANNEL})}&botId=${VX_BOT}&language_code=${VX_LANG}&tts_provider=${VX_TTS}&tts_voice=${URIENCODE(${VX_VOICE})}&stt_provider=${VX_STT})
same => n,Set(CURL_RESULT=${CURL(http://127.0.0.1:8081/session/${SESSION_UUID}/metadata,${META})})
same => n,AudioSocket(${SESSION_UUID},127.0.0.1:8080)
same => n,Hangup()
An empty header gives an empty value, which the gateway ignores, so the .env default applies for that key.
Checking what a call used
GET /session/<uuid>/metadatashows the stored keys.- The metadata POST logs
Session metadata stored for <uuid>with the language and anyTTS:andSTT:provider. - SIP header calls log
SIP header overrides for <session-id>as above. A rejected value logsInvalid x-… in SIP call. - At call start the log shows
Initializing STT provider: <provider> for language: <code>.
Next: Outbound SIP calls and per-call settings, or Text to speech for provider set-up.