Skills
Skill 13 of 14
Turn text into spoken audio with Deepgram.
10 minutes · 2,288 words · 10 sections
Install
npx skills add deepgram/skills --skill text-to-speechnpx skills add deepgram/skills/plugin marketplace add deepgram/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
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.
| 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).
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:
text.encoding, REST returns mp3. For WAV send encoding=linear16&container=wav. Other REST
encodings: opus, flac, aac, mulaw, alaw, with container, bit_rate, sample_rate.model, /v1/speak uses aura-asteria-en, an Aura-1 voice. Always set model.speed accepts 0.7 to 1.5 and works for English and Spanish voices only. Use 0.9 to
1.5 for Spanish voices; values below 0.9 may introduce disfluencies./v1/speak with 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.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 (opens in a new tab). 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.
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"}Flush. Flush ends the turn; the server then sends Flushed and
SpeechMetadata with billing and timing. Treat SpeechMetadata as the end of the turn; Flushed arrives earlier.speech_id per turn in SpeechStarted and SpeechMetadata. Never send one.Connected, with request_id, model_name, model_version, and model_uuids.
The last message on a normal close is SessionMetadata, with cumulative session totals; an Interrupt rebases its
total_audio_duration_ms onto the audio the client actually played.Connected, SpeechStarted, Flushed, SpeechMetadata,
SpeechInterrupted, ConfigureSuccess, ConfigureFailure, Warning, Error, and SessionMetadata.
A Warning carries code and description and leaves the session open. An Error is fatal: every
DOMAIN-NNNN code (MESSAGE-0000, DATA-0000, DATA-0002, BIG-0000, NET-0000 through
NET-0004) is followed by a WebSocket close.{"type":"Interrupt","playback_offset":{"type":"time_ms","value":2340}}.
SpeechInterrupted returns text_spoken and text_remaining; feed text_spoken back into the LLM
context. Without a playback_offset the split is omitted.value is milliseconds played since the session started, not since this turn, and each Interrupt
must exceed the previous offset or it is ignored with INVALID_INTERRUPT_OFFSET. Read
audio_played_ms from SpeechInterrupted as the baseline for the next offset.{"type":"Configure","speed":1.15} changes speed mid-session; the change applies at the next segment
boundary. speed runs 0.5 to 1.5 in 0.05 increments, default 1.0.
ConfigureSuccess with the applied configuration, or ConfigureFailure with
code and description (plus field and value when the failure is tied to one) and keeps the
prior configuration.0.45 and 1.55 return 'speed' must be between 0.5 and 1.5, and 1.07 returns 'speed' must be provided in increments of 0.05.ConfigureFailure codes: SPEED_OUT_OF_RANGE, SPEED_INCREMENT_INVALID, SPEED_NOT_SUPPORTED,
CONTROL_COMBINATION_INVALID (a queued turn still carries a pronunciation control; Flush that
turn first), and INTERNAL_ERROR, for an acceptable configuration the server could not apply.expressivity runs -2 (calm) to 2 (animated), default 0. Values must be whole numbers. An
invalid value is rejected with an HTTP 400 before the WebSocket upgrade completes, so no Connected
message arrives: EXPRESSIVITY_INCREMENT_INVALID for a fraction such as 1.5,
EXPRESSIVITY_OUT_OF_RANGE for a value outside -2 to 2. It is beta, fixed per connection
(Configure cannot change it), and only 0 is validated for production./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"\}.
speed 1.0: on the socket, a pronunciation sent on a session opened with
another speed, or after a Configure that set one, fails the connection with DATA-0002; on batch
the request is a 400 CONTROL_COMBINATION_INVALID.PRONUNCIATION_WARNINGS warning on the
socket and in the dg-warnings header on batch.\{pause:500ms\} is batch only.
speed capped at 1.15 while a pause is present (PAUSE_SPEED_CAP_EXCEEDED). Pauses land within
about 100 ms of the requested duration.DATA-0002, and a pause combined with a
pronunciation is rejected with CONTROL_COMBINATION_INVALID.BREAK_OUT_OF_RANGE, BREAK_INCREMENT_INVALID, BREAKS_LIMIT_EXCEEDED, and
BREAK_SYNTAX_INVALID, which has two triggers: a simple marker without the backslashes, or a
structured marker with them.\{pause:500\} (a bare number is milliseconds), \{pause:500ms\},
\{pause:1.5s\}, and the unescaped structured form {pause:{duration_ms:500}}.SpeechMetadata.controls_applied counts pronunciations_applied, breaks_applied, and
pronunciation_warnings; batch returns dg-pronunciations-applied and dg-breaks-applied response
headers.linear16 by default (see mistake 5). Batch-only parameters
(container, bit_rate, callback, callback_method, priority) and any unknown parameter fail
the connection.NET-0004); send a WebSocket Ping between quiet turns. Every
session closes at 1 hour (NET-0003).POST https://api.deepgram.com/v2/speak?model=flux-haley-en with {"text": "..."} returns one
audio response, mp3 by default, accepts opus, flac, aac, container, bit_rate, and is the
only transport that honors inline pauses.speak.v2;
.NET ships FluxSpeakRESTClient and FluxSpeakWebSocketClient; Rust ships speak::flux; Go ships
pkg/client/speak/v2 from v3.8.0. Only the Rust SDK skill documents Flux TTS fully; the Python
skill has one Flux batch section (its TextBuilder helper), and the JS, Java, Go, and .NET
text-to-speech SDK skills cover /v1/speak only, so take /v2/speak message shapes from this skill.aura-2-{voice}-{lang} in English, Spanish, German, French, Dutch, Italian, and Japanese, plus
twelve Aura-1 English voices named aura-{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, and aura-2-selena-es. Catalog: https://developers.deepgram.com/docs/tts-models (opens in a new tab)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 include flux-haley-en,
flux-alexis-en, and flux-kit-en. Catalog: https://developers.deepgram.com/docs/flux-tts/voices (opens in a new tab)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 (opens in a new tab); do not quote figures from memory.
Wrong auth scheme. API keys go in Authorization: Token <key>. Bearer is only for the short-lived
JWT from POST https://api.deepgram.com/v1/auth/grant. A key sent with Bearer returns 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/models returns the public catalog, not the models your key can
use, and its tts list holds Aura voices only with no flux-* entries, so check Flux TTS voice
names at https://developers.deepgram.com/docs/flux-tts/voices (opens in a new tab).
Parsing audio as JSON. Success bodies are bytes on both endpoints. Branch on status first.
Crossing the families. An Aura voice on /v2/speak and a Flux TTS voice on /v1/speak both fail, and
/v2/speak also rejects a missing model.
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. Speak texts 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_STRIPPED warning per Speak; 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 (opens in a new tab).
Pointing a Voice Agent at api.deepgram.com. The Voice Agent API lives at wss://agent.deepgram.com
and picks the TTS family from agent.speak.provider.version: v2 for Flux TTS, v1 for Aura.
Omitting agent.speak gives Flux TTS with flux-kit-en.
/v2/speak-only
for now, so a non-English agent voice is an Aura-2 (v1) voice or a third-party provider.expressivity inside an agent go on agent.speak.provider; see
https://developers.deepgram.com/docs/voice-agent-tts-controls (opens in a new tab).mp3, opus, flac, aac) or a container such as wav in audio.output
returns INVALID_SETTINGS, so configure an Aura (v1) voice for those formats, including when
agent.speak is omitted.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.
api skill, file references/speak.md.docs skill.starters skill. Features are text-to-speech (Aura REST),
live-text-to-speech (Aura WebSocket), and flux-tts (node, flask, fastapi, django, java only).recipes skill. Recipes cover Aura on /v1/speak only; there
are no Flux TTS recipes yet.examples skill (Aura today). For Twilio with Flux TTS,
follow https://developers.deepgram.com/docs/twilio-and-deepgram-tts (opens in a new tab), which needs deepgram-sdk
7.6.0 or later.setup-mcp skill.deepgram-{js,python,java,go,rust,dotnet}-text-to-speech
skills 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.voice-agent skill and
deepgram-{lang}-voice-agent.speech-to-text skill. Note that “Flux” names both a
speech-to-text product on /v2/listen and this text-to-speech product on /v2/speak.Every page is available as Markdown (append .md to any URL); index at https://developers.deepgram.com/llms.txt (opens in a new tab).
Turn text into spoken audio with Deepgram. Use when someone asks for text-to-speech, TTS, speech synthesis, a synthetic voice, a voice for a voice agent, an IVR prompt, or an audio version of some text, and whenever they mention Aura, Aura-2, Flux TTS, /v1/speak or /v2/speak. Trigger phrases: "text to speech", "TTS", "speak endpoint", "generate speech", "synthesize audio", "read this aloud", "which Deepgram voice", "Aura vs Flux TTS", "TTS with barge-in". Gets an agent to a correct first request, then routes to the api, docs, starters, recipes, examples, setup-mcp and per-language SDK text-to-speech skills.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 5 November 2026.SKILL.md, not by matching a directory convention. One layout observed: skills/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Deepgram Developer Relations, declaring 7 plugins. It is read for editorial metadata only — never as the skill index, which is always the repository tree./deepgram/skills.md, and each skill at its own .md URL.