About text-to-speech
This skill guides developers integrating Deepgram text-to-speech, covering Aura and Flux TTS endpoints, voice selection, streaming and batch requests, and their controls.
Key features
- 01Choose Aura or Flux TTS endpoints
- 02Stream speech over WebSocket
- 03Generate audio with batch requests
- 04Select voices and language variants
- 05Apply speed, pronunciation, and pause controls
Use cases
- 01Build a streaming voice agent with interruption handling
- 02Generate speech files or IVR prompts
- 03Configure multilingual speech output
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ deepgram/ skills --skill text-to-speechAfter installing, type/text-to-speechin Claude Code to confirm it loaded.
Details
From the project READMEDeepgram Text-to-Speech
Deepgram serves two text-to-speech families on separate endpoints, and the voices do not overlap.
Aura voices run only on /v1/speak. Flux TTS voices run only on /v2/speak. /v2/speak is an
additional endpoint. /v1/speak is unchanged and remains supported.
Pick the family first
| Need | Family | Endpoint |
|---|---|---|
| A voice agent that streams LLM output and must survive barge-in | Flux TTS | wss://api.deepgram.com/v2/speak |
| One-shot audio: a file, an IVR prompt, a notification | Flux TTS batch | POST https://api.deepgram.com/v2/speak |
| One response that switches between English and Spanish | Aura-2 codeswitching voice | /v1/speak |
| A non-English voice inside a Voice Agent | Aura-2 | agent.speak.provider.version: "v1" |
An existing aura-2-* or aura-{voice}-en voice you must keep | Aura-2 or Aura-1 | /v1/speak |
Rule of thumb: Flux TTS is the recommended family for every new build, in any of its 42 languages.
Flux TTS voices speak English (American, British, Irish, Australian, Indian, Singaporean, and Filipino
accents) and 41 other languages; the language is the suffix of the model string (flux-anouk-nl is
Dutch). Text normalization (numbers, dates, abbreviations) covers English, German, Dutch, French,
Hindi, Italian, Japanese, Portuguese, Russian, and Spanish; the other 32 languages are Early Access
without it, so write numbers and dates out in words. The non-English voices are served on
api.deepgram.com, api.eu.deepgram.com, and api.in.deepgram.com, not yet on api.au.deepgram.com.
Aura-2 is the previous generation (English, Spanish, German, French, Dutch, Italian, and Japanese) and
Aura-1 the first, English only. Inside a Voice Agent, non-English voices and compressed or
containerized output need an Aura (v1) voice (see mistake 7).
First request: Aura over REST
curl --request POST \
--url "https://api.deepgram.com/v1/speak?model=aura-2-thalia-en&encoding=linear16&container=wav" \
--header "Authorization: Token $DEEPGRAM_API_KEY" \
--header "Content-Type: application/json" \
--data '{"text": "Hello, how can I help you today?"}' \
--output hello.wav \
--fail-with-body --silent || echo "Request failed"
What to expect:
- A 2xx body is binary audio. Errors are JSON. Check the HTTP status before you parse.
- Options go on the query string. The JSON body carries only
text. - With no
encoding, REST returnsmp3. For WAV sendencoding=linear16&container=wav. Other REST encodings:opus,flac,aac,mulaw,alaw, withcontainer,bit_rate,sample_rate. - If you omit
model,/v1/speakusesaura-asteria-en, an Aura-1 voice. Always setmodel. - Aura-2
speedaccepts0.7to1.5and works for English and Spanish voices only. Use0.9to1.5for Spanish voices; values below0.9may introduce disfluencies. - Aura-2 pronunciation control is GA on
/v1/speakwith the same escaped\{"word":"...","pronounce":"<IPA>"\}syntax Flux TTS uses, for English and Spanish voices, with a 2000-character input limit. Aura-2 has no pause control.
Aura over WebSocket
Connect to wss://api.deepgram.com/v1/speak?model=aura-2-thalia-en&encoding=linear16&sample_rate=24000
with the same Authorization: Token header. Send JSON text frames: {"type":"Speak","text":"..."} to
queue text, {"type":"Flush"} to force audio out, {"type":"Clear"} to drop the buffer, and
{"type":"Close"} to end. Audio arrives as binary frames; Metadata, Flushed, Cleared, and
Warning arrive as JSON. Send Flush when the LLM finishes a response. Flush is limited to 20
sends per 60 seconds. Streaming output is raw linear16 (default), mulaw, or alaw only.
Limits on the Aura socket: 2000 characters of text per request (close 1009, payload BIG-0001), 2400
characters per minute into the socket counted across all Speak messages (close 1008, DATA-0001),
and 60 minutes per connection from the initial connect (close 1011, NET-0003); open a new socket for
a longer conversation. The close-frame codes and the dg-error header on a failed upgrade are listed at
https://developers.deepgram.com/docs/tts-troubleshooting-websocket-net-and-data-errors. Regional hosts
api.eu.deepgram.com, api.au.deepgram.com, and api.in.deepgram.com serve /v1/speak,
REST and WebSocket, with the same key.
Flux TTS for voice agents
Connect to wss://api.deepgram.com/v2/speak?model=flux-haley-en. model is required and must be a
flux-* voice. There is no default, and an Aura string is rejected. For in-region processing use
wss://api.eu.deepgram.com/v2/speak, wss://api.au.deepgram.com/v2/speak, or
wss://api.in.deepgram.com/v2/speak; a region that is unavailable fails the request rather than
routing elsewhere.
A session is a sequence of turns. Stream tokens in, then end the turn:
{"type": "Speak", "text": "Sure, I can "}
{"type": "Speak", "text": "help you cancel your subscription."}
{"type": "Flush"}
- Audio starts streaming before you
Flush.Flushends the turn; the server then sendsFlushedandSpeechMetadatawith billing and timing. TreatSpeechMetadataas the end of the turn;Flushedarrives earlier. - The server assigns
speech_idper turn inSpeechStartedandSpeechMetadata. Never send one. - The first message is
Connected, withrequest_id,model_name,model_version, andmodel_uuids. The last message on a normal close isSessionMetadata, with cumulative session totals; anInterruptrebases itstotal_audio_duration_msonto the audio the client actually played. - The server's JSON messages are
Connected,SpeechStarted,Flushed,SpeechMetadata,SpeechInterrupted,ConfigureSuccess,ConfigureFailure,Warning,Error, andSessionMetadata. AWarningcarriescodeanddescriptionand leaves the session open. AnErroris fatal: everyDOMAIN-NNNNcode (MESSAGE-0000,DATA-0000,DATA-0002,BIG-0000,NET-0000throughNET-0004) is followed by a WebSocket close. - On barge-in, stop local playback first, then send
{"type":"Interrupt","playback_offset":{"type":"time_ms","value":2340}}.SpeechInterruptedreturnstext_spokenandtext_remaining; feedtext_spokenback into the LLM context. Without aplayback_offsetthe split is omitted.valueis milliseconds played since the session started, not since this turn, and eachInterruptmust exceed the previous offset or it is ignored withINVALID_INTERRUPT_OFFSET. Readaudio_played_msfromSpeechInterruptedas the baseline for the next offset.
{"type":"Configure","speed":1.15}changes speed mid-session; the change applies at the next segment boundary.speedruns0.5to1.5in0.05increments, default1.0.- The server answers
ConfigureSuccesswith theappliedconfiguration, orConfigureFailurewithcodeanddescription(plusfieldandvaluewhen the failure is tied to one) and keeps the prior configuration. 0.45and1.55return'speed' must be between 0.5 and 1.5, and1.07returns'speed' must be provided in increments of 0.05.ConfigureFailurecodes:SPEED_OUT_OF_RANGE,SPEED_INCREMENT_INVALID,SPEED_NOT_SUPPORTED,CONTROL_COMBINATION_INVALID(a queued turn still carries a pronunciation control;Flushthat turn first), andINTERNAL_ERROR, for an acceptable configuration the server could not apply.
- The server answers
expressivityruns-2(calm) to2(animated), default0. Values must be whole numbers. An invalid value is rejected with an HTTP 400 before the WebSocket upgrade completes, so noConnectedmessage arrives:EXPRESSIVITY_INCREMENT_INVALIDfor a fraction such as1.5,EXPRESSIVITY_OUT_OF_RANGEfor a value outside-2to2. It is beta, fixed per connection (Configurecannot change it), and only0is validated for production.- Pronunciation control is Early Access on Flux TTS
/v2/speak(it is GA on Aura-2/v1/speak, see the Aura REST section). It is an escaped JSON object in the text, on the socket and on batch:\{"word":"dupilumab","pronounce":"duːˈpɪljuːmæb"\}.- Limits: at most 500 per request; IPA at most 128 characters and at most 10 times the length of the source word, with a floor of 15.
- It works only with
speed1.0: on the socket, a pronunciation sent on a session opened with another speed, or after aConfigurethat set one, fails the connection withDATA-0002; on batch the request is a 400CONTROL_COMBINATION_INVALID. - Invalid IPA is still applied best-effort and reported as a
PRONUNCIATION_WARNINGSwarning on the socket and in thedg-warningsheader on batch. - Syntax and IPA guidance: https://developers.deepgram.com/docs/tts-voice-controls
- Pause control
\{pause:500ms\}is batch only.- Limits: 500 to 3000 ms in 100 ms steps, at most 8 per request, text between adjacent pauses, and
speedcapped at1.15while a pause is present (PAUSE_SPEED_CAP_EXCEEDED). Pauses land within about 100 ms of the requested duration. - A pause marker on the socket fails the connection with
DATA-0002, and a pause combined with a pronunciation is rejected withCONTROL_COMBINATION_INVALID. - Other batch 400 codes:
BREAK_OUT_OF_RANGE,BREAK_INCREMENT_INVALID,BREAKS_LIMIT_EXCEEDED, andBREAK_SYNTAX_INVALID, which has two triggers: a simple marker without the backslashes, or a structured marker with them. - Accepted forms are
\{pause:500\}(a bare number is milliseconds),\{pause:500ms\},\{pause:1.5s\}, and the unescaped structured form{pause:{duration_ms:500}}.
- Limits: 500 to 3000 ms in 100 ms steps, at most 8 per request, text between adjacent pauses, and
- Each turn's
SpeechMetadata.controls_appliedcountspronunciations_applied,breaks_applied, andpronunciation_warnings; batch returnsdg-pronunciations-appliedanddg-breaks-appliedresponse headers. - The socket streams raw audio only,
linear16by default (see mistake 5). Batch-only parameters (container,bit_rate,callback,callback_method,priority) and any unknown parameter fail the connection. - Idle sessions close after 60 seconds (
NET-0004); send a WebSocket Ping between quiet turns. Every session closes at 1 hour (NET-0003). - Batch:
POST https://api.deepgram.com/v2/speak?model=flux-haley-enwith{"text": "..."}returns one audio response,mp3by default, acceptsopus,flac,aac,container,bit_rate, and is the only transport that honors inline pauses. - SDKs: every Deepgram SDK ships a Flux TTS client. Python, JavaScript, and Java name it
speak.v2; .NET shipsFluxSpeakRESTClientandFluxSpeakWebSocketClient; Rust shipsspeak::flux; Go shipspkg/client/speak/v2from v3.8.0. Only the Rust SDK skill documents Flux TTS fully; the Python skill has one Flux batch section (itsTextBuilderhelper), and the JS, Java, Go, and .NETtext-to-speechSDK skills cover/v1/speakonly, so take/v2/speakmessage shapes from this skill.
Voices
- Aura:
aura-2-{voice}-{lang}in English, Spanish, German, French, Dutch, Italian, and Japanese, plus twelve Aura-1 English voices namedaura-{voice}-en. Five Spanish voices switch between English and Spanish within one request:aura-2-aquila-es,aura-2-carina-es,aura-2-diana-es,aura-2-javier-es, andaura-2-selena-es. Catalog: https://developers.deepgram.com/docs/tts-models - Flux TTS:
flux-{voice}-{language}with a two-letter language suffix, in English and 41 other languages. Regional variants share the suffix: Brazilian and European Portuguese are both-pt, Flemish is-nl, Swiss German is-de, and Mandarin, Taiwanese Mandarin, and Cantonese are all-zh, so pick the voice by name from the catalog. Featured English voices includeflux-haley-en,flux-alexis-en, andflux-kit-en. Catalog: https://developers.deepgram.com/docs/flux-tts/voices
Pricing
Text-to-speech is billed per 1,000 characters of input text, for Flux TTS, Aura-2, and Aura-1 alike. Rates differ by model and plan and change over time. Read them at https://deepgram.com/pricing; do not quote figures from memory.
Common mistakes
-
Wrong auth scheme. API keys go in
Authorization: Token <key>.Beareris only for the short-lived JWT fromPOST https://api.deepgram.com/v1/auth/grant. A key sent withBearerreturns 401. -
Misreading a model error. A model name that does not exist, including a misspelling, is a 400
{"err_code":"Bad Request","err_msg":"Bad Request: No such model/language/tier combination found."}. A model that exists but your project cannot use is a 403{"err_code":"INSUFFICIENT_PERMISSIONS","err_msg":"Project does not have access to the requested model."}. Fix a 400 by checking the name against the catalogs above; ask for access only on a 403.GET https://api.deepgram.com/v1/modelsreturns the public catalog, not the models your key can use, and itsttslist holds Aura voices only with noflux-*entries, so check Flux TTS voice names at https://developers.deepgram.com/docs/flux-tts/voices. -
Parsing audio as JSON. Success bodies are bytes on both endpoints. Branch on status first.
-
Crossing the families. An Aura voice on
/v2/speakand a Flux TTS voice on/v1/speakboth fail, and/v2/speakalso rejects a missingmodel. -
Asking a WebSocket for
mp3. Streaming is raw audio on both endpoints. Use REST for compressed output. -
Expecting Flux TTS to clean up your text.
Speaktexts are concatenated verbatim, so"Hello world."then"How are you?"becomes"Hello world.How are you?". Insert a space when you stitch a reply, a tool result, and another reply.Send plain text. SSML is not interpreted; the only markup Flux TTS honors is its own escaped controls, pronunciation on both transports and pause on batch. Recognized SSML, ElevenLabs, and Cartesia tags are stripped, with one
INPUT_MARKUP_STRIPPEDwarning perSpeak; markup the detector does not match (Markdown, HTML, custom XML) is forwarded verbatim and may be spoken. See https://developers.deepgram.com/docs/flux-tts/client-messages. -
Pointing a Voice Agent at api.deepgram.com. The Voice Agent API lives at
wss://agent.deepgram.comand picks the TTS family fromagent.speak.provider.version:v2for Flux TTS,v1for Aura. Omittingagent.speakgives Flux TTS withflux-kit-en.- The agent accepts the English Flux TTS voices only; the other 41 languages are
/v2/speak-only for now, so a non-English agent voice is an Aura-2 (v1) voice or a third-party provider. - Speed and
expressivityinside an agent go onagent.speak.provider; see https://developers.deepgram.com/docs/voice-agent-tts-controls. - An inline pause marker is not spoken and no error is returned, so text containing one goes silent; keep pacing to punctuation and digit grouping.
- A compressed encoding (
mp3,opus,flac,aac) or a container such aswavinaudio.outputreturnsINVALID_SETTINGS, so configure an Aura (v1) voice for those formats, including whenagent.speakis omitted.
- The agent accepts the English Flux TTS voices only; the other 41 languages are
-
Using voice controls outside the languages that have them. Flux TTS
speed, pause, and pronunciation are documented for English voices only, and Aura-2 speed and pronunciation cover English and Spanish only. On any other voice, pace with punctuation instead.
Use a different skill when
- You need every parameter, enum, or message schema:
apiskill, filereferences/speak.md. - You need a docs page you cannot name:
docsskill. - You want a runnable app:
startersskill. Features aretext-to-speech(Aura REST),live-text-to-speech(Aura WebSocket), andflux-tts(node, flask, fastapi, django, java only). - You want a snippet under 50 lines:
recipesskill. Recipes cover Aura on/v1/speakonly; there are no Flux TTS recipes yet. - You are wiring a third-party platform:
examplesskill (Aura today). For Twilio with Flux TTS, follow https://developers.deepgram.com/docs/twilio-and-deepgram-tts, which needsdeepgram-sdk7.6.0 or later. - You want the docs inside your coding tool:
setup-mcpskill. - You want idiomatic code in one language: the
deepgram-{js,python,java,go,rust,dotnet}-text-to-speechskills from the SDK repositories (npx skills add deepgram/deepgram-python-sdk, and so on). Only the Rust SDK skill documents Flux TTS fully; see the SDKs bullet in the Flux TTS section. - You want Deepgram to run speech-to-text, the LLM, and TTS in one connection:
voice-agentskill anddeepgram-{lang}-voice-agent. - You are transcribing rather than synthesizing:
speech-to-textskill. Note that "Flux" names both a speech-to-text product on/v2/listenand this text-to-speech product on/v2/speak.
Sources
Every page is available as Markdown (append .md to any URL); index at https://developers.deepgram.com/llms.txt.
- Model families and regions: https://developers.deepgram.com/docs/tts-models-languages-overview https://developers.deepgram.com/reference/regional-endpoints
- Aura: https://developers.deepgram.com/docs/text-to-speech https://developers.deepgram.com/docs/streaming-text-to-speech https://developers.deepgram.com/docs/tts-models https://developers.deepgram.com/docs/tts-voice-controls https://developers.deepgram.com/docs/tts-encoding https://developers.deepgram.com/docs/tts-media-output-settings https://developers.deepgram.com/docs/tts-ws-flush https://developers.deepgram.com/docs/tts-ws-clear https://developers.deepgram.com/docs/tts-ws-close https://developers.deepgram.com/docs/tts-troubleshooting-websocket-net-and-data-errors https://developers.deepgram.com/docs/text-to-speech-prompting
- Flux TTS: https://developers.deepgram.com/docs/flux-tts/overview https://developers.deepgram.com/docs/flux-tts/feature-overview https://developers.deepgram.com/docs/flux-tts/quickstart https://developers.deepgram.com/docs/flux-tts/batch https://developers.deepgram.com/docs/flux-tts/batch-vs-streaming https://developers.deepgram.com/docs/flux-tts/voices https://developers.deepgram.com/docs/flux-tts/client-messages https://developers.deepgram.com/docs/flux-tts/server-messages https://developers.deepgram.com/docs/flux-tts/state https://developers.deepgram.com/docs/flux-tts/context https://developers.deepgram.com/docs/flux-tts/interrupt-handling https://developers.deepgram.com/docs/flux-tts/migrating https://developers.deepgram.com/docs/flux-tts/voice-agent https://developers.deepgram.com/docs/flux-tts/template-apps https://developers.deepgram.com/docs/tts-expressivity
- API reference: https://developers.deepgram.com/reference/text-to-speech/speak-request https://developers.deepgram.com/reference/text-to-speech/speak-streaming https://developers.deepgram.com/reference/text-to-speech/speak-flux https://developers.deepgram.com/reference/speak/v-2/audio/generate https://developers.deepgram.com/reference/manage/models/list
- Auth, errors, agent, integrations, pricing: https://developers.deepgram.com/reference/authentication https://developers.deepgram.com/reference/auth/tokens/grant https://developers.deepgram.com/docs/errors https://developers.deepgram.com/docs/voice-agent-tts-models https://developers.deepgram.com/docs/voice-agent-tts-controls https://developers.deepgram.com/reference/voice-agent/voice-agent https://developers.deepgram.com/docs/twilio-and-deepgram-tts https://deepgram.com/pricing