VoiceML / Text-to-speech
Speak text on a call with built-in voices or your own premium provider.
VoiceML turns text into spoken audio on a call using the Twilio-compatible <Say> verb. The same text-to-speech settings on your account also power agent speech in <Connect><ConversationRelay>. This guide covers how to use <Say>, the built-in voices included with every account, and how to connect your own premium voice provider for natural, studio-quality speech.
Free trial Compatibility matrix
Using <Say>
Quick start
<Say> reads text aloud. The simplest form uses the default voice:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Thank you for calling. Please hold.</Say>
</Response>
To pick a different voice or language, use the voice and language attributes:
<Say voice="man">Press one for sales.</Say>
<Say language="es-ES">Gracias por llamar.</Say>
<Say voice="man" language="fr-FR">Appuyez sur le un.</Say>
Attributes
| Attribute | Purpose | Default |
|---|---|---|
voice | Which voice speaks the text. | Standard female |
language | Language/locale as a BCP-47 code (e.g. en-US, es-ES). | en-US |
loop | How many times to repeat the text. | 1 |
Repeat a message three times:
<Say loop="3">This call is being recorded.</Say>
Voice names may only contain letters, digits, periods, underscores, and hyphens (A–Z a–z 0–9 . _ -). Other characters are rejected with a clear error.
Built-in voices
Every account includes built-in voices at no additional setup. Leave the TTS provider unset on your Account page (or choose default — built-in voices) to use them.
Voice name compatibility
You don't need to know internal voice ids. Use the same attributes Twilio documents:
voice value |
Result |
|---|---|
woman | Standard female voice |
alice | Standard female voice |
man | Standard male voice |
| (omitted) | Standard female voice (default) |
Gender comes from voice: man / male select a male voice; woman, female, alice, empty, and most other values select a female voice.
Language comes from language: Spanish, French, and German tags select that language; English and any unsupported language select English.
<Say> attributes |
Voice used |
|---|---|
| (none) | English, female |
voice="man" | English, male |
voice="woman" | English, female |
language="es-ES" | Spanish, female |
voice="man" language="es-MX" | Spanish, male |
voice="Polly.Matthew" language="de-DE" | German, male |
Only the primary part of the language code matters — es, es-ES, and es-MX all select Spanish.
Languages supported
The built-in voices speak four languages, each with a male and a female option:
| Language | language value |
Female | Male |
|---|---|---|---|
| English (US) | en-US / en | Yes | Yes |
| Spanish | es-ES / es | Yes | Yes |
| French | fr-FR / fr | Yes | Yes |
| German | de-DE / de | Yes | Yes |
Voice catalog (optional)
You can also select a voice directly by id or friendly name (either works, case-insensitive):
| Voice id | Name | Language | Gender |
|---|---|---|---|
en-US-female | Lily (default) | English | female |
en-US-male | Michael | English | male |
es-ES-female | Lucia | Spanish | female |
es-ES-male | Carlos | Spanish | male |
fr-FR-female | Chloé (or Chloe) | French | female |
fr-FR-male | Pierre | French | male |
de-DE-female | Kerstin | German | female |
de-DE-male | Thorsten | German | male |
<Say voice="es-ES-male">Bienvenido.</Say>
<Say voice="de-DE-female">Willkommen.</Say>
Defaults and graceful fallback
- Default voice: standard English female (Lily) when
voiceandlanguageare omitted. - Unsupported language: the text is still spoken (in English) rather than failing, so a call never ends in silence.
- Never silence: a valid
<Say>always produces audio. If the requested voice can't be rendered, VoiceML automatically falls back so the caller always hears the prompt.
Migration-compatible voice names
VoiceML accepts Twilio-style voice names — for example Polly.Joanna, Polly.Matthew, or Google-prefixed names — and maps them to the closest matching built-in voice by gender. Your existing voice markup keeps working without edits. To reproduce a specific premium Twilio voice exactly, configure Bring Your Own Voice with the matching provider below.
Bring Your Own Voice
For studio-quality, natural-sounding speech and a much larger catalog of voices and languages, connect your own account with a supported text-to-speech provider. You bring the provider credentials; VoiceML uses them to synthesize your <Say> prompts and ConversationRelay agent speech.
Supported providers
| Provider | Service | What you configure |
|---|---|---|
| Amazon Polly | Polly | Access key, secret, region, voice, engine |
| Microsoft Azure | Cognitive Services Speech | API key, region, voice name |
| ElevenLabs | Text-to-Speech | API key, voice ID, model ID |
| Deepgram | Aura | API key, voice model |
| Cartesia | Sonic | API key, voice ID, model, API version |
How to enable a provider
Configure a premium provider from your Account page in the VoiceML portal (section Text-to-speech (TTS)):
- Open the Account page and find the Text-to-speech (TTS) section.
- Choose the provider you want from the dropdown, or leave it on default — built-in voices to use the standard voices above.
- Expand that provider's section and enter its credentials plus a default voice.
- Save. New calls immediately use the new voice — no restart or redeploy needed.
Credentials in the portal are write-only — leave a field blank to keep the value already saved.
Once a provider is configured, every <Say> on your account uses it automatically. You don't need to change your voice markup unless you want to override the voice on a specific prompt.
Voice resolution order
The voice that actually speaks is resolved in this order:
- Per-call — the
voiceattribute on the<Say>element, if set. - Account default — the default voice you configured in the portal for your provider.
- Provider default — the provider's built-in default voice when you leave the portal voice field empty.
Cartesia has no built-in default voice, so always configure a default voice in the portal or pass voice on every <Say>.
Provider setup guides
Each guide walks through portal setup with concrete examples and popular voice names. After saving, test on a new call.
Amazon Polly
What you need: an AWS account with Polly enabled, an IAM access key and secret with permission to call Polly, and the AWS region where you created the key (for example us-east-1).
Portal fields (Account → Text-to-speech → AWS Polly):
| Field | Example |
|---|---|
| Access key ID | AKIA… |
| Secret access key | (your secret — write-only) |
| Region | us-east-1 |
| Voice | Joanna |
| Engine | neural |
Popular voices:
| Name | Voice value | Notes |
|---|---|---|
| Joanna | Joanna | Default US English female; platform default if voice left blank |
| Matthew | Matthew | US English male |
| Ruth | Ruth | US English female (neural) |
| Stephen | Stephen | US English male (neural) |
We recommend the neural engine for the most natural Polly speech. Use standard for legacy voices or long-form for extended narration.
Example voice markup (with Polly configured as your provider):
<Response>
<Say voice="Matthew">Your order has shipped.</Say>
<Say voice="Joanna" language="es-ES">Su pedido ha sido enviado.</Say>
</Response>
Microsoft Azure
What you need: an Azure Speech resource and its subscription key, plus the region where the resource was created (for example eastus). The region must match your resource — a wrong region returns an authentication error.
Portal fields (Account → Text-to-speech → Azure Cognitive Services Speech):
| Field | Example |
|---|---|
| API key | (your subscription key — write-only) |
| Region | eastus |
| Voice | en-US-JennyNeural |
Popular voices:
| Name | Voice value | Language |
|---|---|---|
| Jenny | en-US-JennyNeural | US English female; platform default if voice left blank |
| Guy | en-US-GuyNeural | US English male |
| Aria | en-US-AriaNeural | US English female |
The voice name encodes the language — pick a voice from the Azure voice gallery that matches the language of your text.
Example voice markup:
<Response>
<Say voice="en-US-GuyNeural">Press one to confirm your appointment.</Say>
</Response>
ElevenLabs
What you need: an ElevenLabs API key and the voice ID of the voice you want as your default. You can find voice IDs in the ElevenLabs voice library or when creating a custom voice.
Portal fields (Account → Text-to-speech → ElevenLabs):
| Field | Example |
|---|---|
| API key | (your key — write-only) |
| Voice ID | 21m00Tcm4TlvDq8ikWAM |
| Model ID | eleven_turbo_v2_5 |
Popular voices:
| Name | Voice ID | Notes |
|---|---|---|
| Rachel | 21m00Tcm4TlvDq8ikWAM | Platform default if voice left blank |
| Adam | pNInz6obpgDQGcFmaJgB | Deep male |
| Bella | EXAVITQu4vr4xnSDxMaL | Soft female |
Popular models: eleven_turbo_v2_5 (fast, English-focused) or eleven_multilingual_v2 (broader language support). Leave Model ID empty to use ElevenLabs' default for your account.
Example voice markup:
<Response>
<Say voice="pNInz6obpgDQGcFmaJgB">Hello, this is a reminder about your appointment tomorrow.</Say>
</Response>
Pass the ElevenLabs voice ID in the voice attribute, not the display name.
Deepgram Aura
What you need: a Deepgram API key with text-to-speech access. Aura voice models encode both the voice and its language in a single id (for example aura-2-thalia-en).
Portal fields (Account → Text-to-speech → Deepgram Aura):
| Field | Example |
|---|---|
| API key | (your key — write-only) |
| Voice | aura-2-thalia-en |
Popular voices:
| Name | Voice value | Language |
|---|---|---|
| Thalia | aura-2-thalia-en | US English female; platform default if voice left blank |
| Asteria | aura-2-asteria-en | US English female |
| Helena | aura-2-helena-en | US English female |
Example voice markup:
<Response>
<Say voice="aura-2-asteria-en">Thanks for calling. One moment while we connect you.</Say>
</Response>
Cartesia Sonic
What you need: a Cartesia API key and a voice ID from the Cartesia voice catalog or playground. Cartesia voices are referenced by UUID — copy the ID from your Cartesia dashboard.
Portal fields (Account → Text-to-speech → Cartesia Sonic):
| Field | Example |
|---|---|
| API key | (your key — write-only) |
| Voice ID | f786b574-daa5-4673-aa0c-cbe3e8534c02 |
| Model | sonic-3 |
| API version | (leave blank unless Cartesia instructs otherwise) |
Popular voices:
| Name | Voice ID | Style |
|---|---|---|
| Katie | f786b574-daa5-4673-aa0c-cbe3e8534c02 | Friendly, clear — great for support lines |
| Jameson | a5136bf9-224c-4d76-b823-52bd5efcffcc | US English male |
| Skylar | db6b0ed5-d5d3-463d-ae85-518a07d3c2b4 | US English female |
Cartesia requires a voice ID — configure one as your account default in the portal. If you leave Model empty, VoiceML uses the current Sonic model (sonic-3).
Example voice markup:
<Response>
<Say voice="f786b574-daa5-4673-aa0c-cbe3e8534c02">Your verification code is 4 8 2 9.</Say>
</Response>
Choosing a voice per call
You can override the account default on any individual <Say> by setting the voice attribute to a value from your provider's catalog:
<!-- Polly: voice name -->
<Say voice="Matthew">Your order has shipped.</Say>
<!-- Azure: full neural voice name -->
<Say voice="en-US-GuyNeural">Press one to confirm.</Say>
<!-- ElevenLabs or Cartesia: voice ID -->
<Say voice="21m00Tcm4TlvDq8ikWAM">Hello from Rachel.</Say>
<!-- Deepgram: Aura model id -->
<Say voice="aura-2-helena-en">Thanks for holding.</Say>
The language attribute still applies where your provider uses it. With Azure, Polly, and Deepgram Aura, the voice identifier itself usually defines the language — pick a voice that natively speaks your target language.
Migrating from Twilio
VoiceML uses the same <Say> syntax as Twilio:
- Existing markup with
voice="woman",voice="man", orvoice="alice"works unchanged. - Twilio-style names like
Polly.Joannamap to the closest built-in voice so calls keep working during migration. - When you need the exact Polly, Azure, ElevenLabs, or other premium voice Twilio offered, configure the matching provider under Bring Your Own Voice and set the provider's voice identifier in
voice.
Troubleshooting
| Symptom | What to check |
|---|---|
| Speech sounds like the basic built-in voice, not my provider | Confirm the correct provider is selected on the Account page, credentials are saved, and the API key or region matches your provider account. |
| Wrong language spoken | Pick a voice from your provider that supports that language. Built-in voices only cover English, Spanish, French, and German. |
| Cartesia uses the wrong voice or no speech | Cartesia requires a voice ID — set a default in the portal or pass voice on every <Say>. |
| Azure returns an auth error | The Region in the portal must match the region where your Azure Speech resource was created. |
| Polly voice sounds flat | Switch Engine to neural for supported voices. |
| A configuration change didn't seem to apply | Changes take effect on the next call. Confirm the Account page save succeeded and place a fresh test call. |
Empty <Say> does nothing | There must be text between the opening and closing tags. |