About speech-to-text
A Deepgram skill that guides developers through choosing Nova or Flux STT and making an initial transcription request. It focuses on model selection, endpoints, and key differences; detailed parameter reference belongs to the separate `api` skill.
Key features
- 01Compare Nova and Flux STT
- 02Select endpoints and models
- 03Start prerecorded transcription
- 04Stream audio over WebSockets
- 05Configure turn detection
Use cases
- 01Transcribe recorded audio
- 02Generate captions or subtitles
- 03Build voice interfaces with turn detection
- 04Choose a Deepgram speech model
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ deepgram/ skills --skill speech-to-textAfter installing, type/speech-to-textin Claude Code to confirm it loaded.
Details
From the project READMEDeepgram Speech-to-Text
Deepgram transcribes audio with two model families on two endpoints. Pick the family first; the endpoint, the parameters, and the message shapes all follow from that choice. This skill gets a first request working and names the skill to open next. It does not repeat the full parameter reference; that lives in the api skill.
Pick the model family first
| Nova | Flux STT | |
|---|---|---|
| Model names | nova-3 (alias of nova-3-general), nova-3-medical, nova-3-pharma | flux-general-en (English), flux-general-multi (10 languages) |
| Endpoint | /v1/listen, REST and WebSocket | /v2/listen, WebSocket only |
| Output | A transcript stream | TurnInfo events carrying turn state and a transcript per turn |
| Turn detection | None built in; you use endpointing and your own logic | Built in: StartOfTurn, EagerEndOfTurn, TurnResumed, EndOfTurn |
| Formatting and analysis | smart_format, diarize_model, summarize, sentiment, topics, intents, redaction | Word timestamps, numerals, redact (numbers or aggressive_numbers), keyterm, profanity_filter, mip_opt_out, tag; no smart formatting, no diarization |
| Language | language=<code>, or language=multi for code-switching, which language_hint biases | The model name selects the language; language_hint biases flux-general-multi |
Decision rule:
- Choose Nova when you transcribe recorded files, generate captions or subtitles, need speaker labels, need summaries or sentiment, or stream audio where your own code decides when a phrase ends.
- Choose Flux STT when a person is talking to software and the software must know when they stopped: voice agents, phone assistants, IVR, agent assist. Flux has no prerecorded mode.
- Choose neither when you want Deepgram to also run the language model and speak the reply. That is the Voice Agent API, served from a separate host,
agent.deepgram.com. Open thevoice-agentskill.
First request: Nova on a prerecorded file
Create a key at https://console.deepgram.com and export it as DEEPGRAM_API_KEY. The key goes in the Authorization header with the Token scheme. Always pass model; without it the API falls back to base.
curl -s -X POST 'https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true' \
-H "Authorization: Token $DEEPGRAM_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"url":"https://dpgr.am/spacewalk.wav"}'
The transcript is at results.channels[0].alternatives[0].transcript. To send a local file instead, set Content-Type to the audio type (for example audio/wav) and pass --data-binary @file.wav with no JSON body.
Nova options you will reach for, all query parameters on /v1/listen:
smart_format=trueadds punctuation, paragraphs, and number formatting. It turns onpunctuate, so do not set both.diarize_model=latestlabels speakers. It replaces the deprecateddiarize=true; a request that sets both is rejected. Streaming acceptslatestandv1only.language=multitranscribes code-switched speech across the 55 Nova-3 multilingual languages. Any single language code works too; the default isen.language_hint=<code>, repeated per language (language_hint=en&language_hint=es), biaseslanguage=multitoward the languages you expect without restricting it. It is ignored with any otherlanguage, a code outside the Nova-3 multilingual list is a 400 (a rejected WebSocket handshake when streaming), and hints are fixed for the life of a stream. Responses echo the normalized hints inlanguages_hinted.keyterm=<term>boosts names, product terms, and jargon. It is accepted on Nova-3 and Flux STT only; other models, Nova-2 for example, usekeywordsinstead. Repeat the parameter once per term. The limit is 500 tokens across all keyterms in a request, and exceeding it fails the request withKeyterm limit exceeded; Deepgram's guidance is to stay well under it with the 20 to 50 terms that matter. Commas, semicolons, andterm:weightare not rejected; the API treats the whole value as one literal term, so nothing you intended gets boosted.summarize=v2,sentiment=true,topics=true, andintents=trueadd audio intelligence. They run on prerecorded English audio only.- Live streaming uses
wss://api.deepgram.com/v1/listen?model=nova-3, the sameAuthorizationheader, and binary audio frames. Send{"type":"KeepAlive"}as a text frame every 3 to 5 seconds during silence, as the keep-alive page says; after 10 seconds without audio orKeepAlivethe connection closes withNET-0001. Finish with{"type":"CloseStream"}. To change vocabulary or formatting mid-stream, send{"type":"Configure","keyterms":["routing number"],"features":{"numerals":true}}:keytermsreplaces the whole list (including thekeytermquery parameters;[]clears it, omitted ornullkeeps it) and works on Nova-3 models only, andfeaturestoggles booleans such asnumerals. Wait forConfigureSuccessorConfigureFailurebefore sending the next one; a failure (CONFIGURE_KEYTERMS_NOT_SUPPORTED,CONFIGURE_KEYTERM_LIMIT_EXCEEDED,CONFIGURE_ALREADY_PENDING,CONFIGURE_INTERNAL_ERROR) applies none of the message and leaves the stream running. Regional hosts take the same path and the same key:wss://api.eu.deepgram.com/v1/listen,wss://api.au.deepgram.com/v1/listen,wss://api.in.deepgram.com/v1/listen.
Flux STT: conversational audio with turn detection
Connect over WebSocket. Flux has no REST path.
wss://api.deepgram.com/v2/listen?model=flux-general-en&encoding=linear16&sample_rate=16000
Send the same Authorization: Token header. Audio must be mono. For raw audio (linear16, linear32, mulaw, alaw, opus, ogg-opus) encoding and sample_rate are required; for WAV, Ogg, or WebM containers omit both. Send 80 ms chunks. Flux STT has no KeepAlive message: WebSocket pings replace it, with a 60-second timeout. For in-region processing use wss://api.eu.deepgram.com/v2/listen, wss://api.au.deepgram.com/v2/listen, or wss://api.in.deepgram.com/v2/listen with the same key.
Two query parameters on /v2/listen to note:
redacttakesnumbersoraggressive_numbers; any other value fails the handshake with 400. Each redacted span becomes a single*, not[REDACTED]or an entity tag.profanity_filter=trueworks on/v2/listen,language=multiincluded.
The server sends Connected, then a stream of TurnInfo messages. Each carries event, turn_index, transcript, words with timestamps, and end_of_turn_confidence. The event values:
Update: roughly every 0.25 s of audio while a turn is in progress.StartOfTurn: the speaker began. Use it to interrupt your agent (barge-in).EndOfTurn: the speaker finished. Send the transcript to your language model. It carriestrigger:model,manual, ortimeout.EagerEndOfTurnandTurnResumed: emitted only when you seteager_eot_threshold. Start drafting a reply on the first; cancel it on the second. TheEndOfTurntranscript matches theEagerEndOfTurntranscript exactly. Expect 50 to 70% more LLM calls in exchange for roughly 100 to 200 ms less end-to-end latency; start withEndOfTurnonly.
Three query parameters tune turn detection, and all three can change mid-stream through the Configure message below:
| Parameter | Range | Default | Effect |
|---|---|---|---|
eot_threshold | 0.5 to 1.0 | 0.7 | Confidence needed for EndOfTurn. 1.0 suppresses model detection. |
eager_eot_threshold | 0.3 to 0.9 | unset | Enables EagerEndOfTurn. Lower values fire earlier with more false starts. Must be less than or equal to eot_threshold. |
eot_timeout_ms | 500 to 60000 | 5000 | Silence that forces EndOfTurn regardless of confidence. |
Client control messages, each a JSON text frame:
{"type":"Configure","thresholds":{"eot_threshold":0.8},"keyterms":["Deepgram"],"numerals":true}changes thresholds, keyterms,language_hints, ornumeralswithout reconnecting.- Shape and atomicity: the turn-detection thresholds go under
thresholds, as in the example; omitted fields keep their values. All fields in one message apply together or not at all: if one fails validation, none take effect. keyterms: the array replaces the whole list and holds at most 100 plain terms (noterm:weightsyntax).language_hints:[]clears the hints and reverts to auto-detect, while omitting the field or sendingnullkeeps them.numerals: starts from thenumeralsquery parameter and applies to transcripts Flux STT sends after it processes the update, never to transcripts already sent. It must be a JSON boolean: the string"true"fails schema validation, Flux STT returns anErrorwith codeUNPARSABLE_CLIENT_MESSAGE, and the connection closes.- The reply is
ConfigureSuccess, which echoes the full active configuration includingnumerals, orConfigureFailure, which carriescodeanddescriptionnaming the rejected field and leaves the previous configuration in place.
- Shape and atomicity: the turn-detection thresholds go under
{"type":"ForceEndTurn"}(added August 28, 2026) ends the current turn on your own signal: a push-to-talk release, a DTMF tone, a send button. Flux STT emitsEndOfTurnwith"trigger":"manual". With no active turn the message is ignored and aWarningwith codeFORCE_END_TURN_NO_ACTIVE_TURNcomes back. Seteot_threshold=1.0to drive every turn yourself, keepingeot_timeout_mshigh as a backstop ("trigger":"timeout").- SDK methods: JS 5.9.0
sendForceEndTurn, Python 7.8.0send_force_end_turn, Java 0.9.0sendForceEndTurn, Go 3.8.0ForceEndTurn(), Rust 0.10.1force_end_turn(), .NET 7.1.0SendForceEndTurn()on the concreteFluxWebSocketClient, not the interface.
- SDK methods: JS 5.9.0
{"type":"CloseStream"}finishes decoding the audio already received, emits the matchingUpdatemessages, and closes the connection without a WebSocket close status code. It does not finalize the active turn: noEndOfTurnis emitted, so the last message is an interimUpdate. To end on a final transcript sendForceEndTurnfirst, thenCloseStream; messages are processed in order, so the turn ends and then the connection closes. Sent the other way round, theForceEndTurnhas no effect.
For non-English or mixed-language calls use model=flux-general-multi, optionally with repeated language_hint=<code> parameters (for example language_hint=en&language_hint=es). Without hints the model detects the language itself. TurnInfo then includes languages and languages_hinted. numerals formats every number on flux-general-en; on flux-general-multi it formats English, Spanish, French, German, Russian, Portuguese, Italian, and Dutch, and leaves Hindi and Japanese numbers as spoken.
Common mistakes
Authorization: Bearer <api key>returns 401. API keys useAuthorization: Token <key>.Beareris only for the short-lived JWT thatPOST /v1/auth/grantissues.- A 403 with
{"err_code":"INSUFFICIENT_PERMISSIONS","err_msg":"Project does not have access to the requested model."}comes back both for a misspelled model name and for a real model the project cannot use. The body carries arequest_id. Check the spelling before asking for access.GET https://api.deepgram.com/v1/modelslists the public catalog;GET /v1/projects/{project_id}/modelslists your project's models. There is no model namednova-3-conversational; conversational audio is Flux,flux-general-en. The public catalog does not list the Flux model names, so the Flux docs are the source for those. - Flux on
/v1/listendoes not work, andmodel=fluxis not a valid value. Use/v2/listenwithflux-general-enorflux-general-multi. language=enorlanguage=multion Flux is wrong. The model name selects the language. On/v2/listen,language_hintis accepted only byflux-general-multiand returns 400 on any other model.- Setting
encodingorsample_ratefor containerized audio (WAV, Ogg, WebM) causes errors or garbled output. Omit both and let the container declare the format. ForceEndTurnon/v1/listenreturns an error; it exists only on Flux.smart_format,diarize, and the intelligence parameters are not available on/v2/listen. Speaker labels and summaries are a Nova job.- A
KeepAlivesent as a binary frame is mishandled. Send control messages as text frames and audio as binary frames. {"type":"Configure","features":{"numerals":true}}is the/v1/listenform. Flux STT rejects thefeaturesnesting and closes the connection; on/v2/listensendnumeralsas a top-level field,{"type":"Configure","numerals":true}.
Pricing
Deepgram bills speech-to-text per minute of audio. Figures change, so read them at https://deepgram.com/pricing rather than from any skill.
Use a different skill when
- You need every parameter, response schema, or message field:
apiskill, filereferences/listen.md. - You want the documentation page for a topic:
docsskill. The pages this skill leans on are listed under Sources. - You want a runnable app with a UI:
startersskill (thetranscription,live-transcription, andfluxfeatures). - You want a one-feature snippet under 50 lines:
recipesskill, https://github.com/deepgram/recipes. - You are wiring Deepgram into Twilio, LiveKit, Pipecat, LangChain, or another platform:
examplesskill. - You want language-idiomatic SDK code: install
deepgram-{js,python,java,go,rust,dotnet}-speech-to-textfor Nova anddeepgram-{lang}-conversational-sttfor Flux STT from the matching SDK repository (npx skills add deepgram/deepgram-python-sdk, and so on). - You want mid-stream
numeralsthroughConfigurefrom an SDK: thedeepgram-{lang}-conversational-sttskills do not cover it, so take the message shape from theConfigurebullet in this skill. The JavaScript SDK sends it from 5.13.0 (socket.sendConfigure({type:"Configure", numerals:true})), the Python SDK from 7.11.0 (connection.send_configure(ListenV2Configure(numerals=True))), the Java SDK from 0.10.2 (sendConfigure(ListenV2Configure.builder().numerals(true).build())), and the .NET SDK from 7.2.0 (Numeralson the FluxConfigureSchema). - You want mid-stream
numeralson the Go (through 3.10.0) or Rust (through 0.14.0) SDK: their Flux Configure types carry nonumeralsfield, so send the raw JSON Configure message or setnumeralson the connection URL. - You want the Nova
/v1/listenConfiguremessage orlanguage_hintfrom an SDK: JS hasConfigurefrom 5.15.0 andConfigureSuccess,ConfigureFailure, andlanguage_hintfrom 5.16.0; Python hasConfigurefrom 7.13.0, the replies from 7.14.0, andlanguage_hintfrom 7.15.0; Java hasConfigurefrom 0.11.1 and the replies pluslanguageHintfrom 0.11.2. .NET 7.2.0 sendsConfigurethroughSendConfigurebut types no replies (its own docs say rejections arrive asError) and has no/v1/listenlanguage_hint. Go and Rust have none of these, so send raw JSON and addlanguage_hintto the URL yourself. - You want analysis and not just the transcript (
summarize,sentiment,topics,intents,detect_entitieson/v1/listen):audio-intelligenceskill. For text you already have,/v1/readand thetext-intelligenceskill. - You want text-to-speech or a full voice agent: the
text-to-speechorvoice-agentskill. - You want a shell command rather than application code:
cliskill. - You want the docs queryable from your coding tool:
setup-mcpskill.
Sources
- Getting started: https://developers.deepgram.com/docs/stt/getting-started
- Nova prerecorded: https://developers.deepgram.com/docs/pre-recorded-audio
- Nova live streaming: https://developers.deepgram.com/docs/live-streaming-audio and https://developers.deepgram.com/docs/audio-keep-alive
- Models and languages: https://developers.deepgram.com/docs/models-languages-overview
- Multilingual code switching: https://developers.deepgram.com/docs/multilingual-code-switching
- Smart Format, diarization, keyterms: https://developers.deepgram.com/docs/smart-format, https://developers.deepgram.com/docs/diarization, https://developers.deepgram.com/docs/keyterm
- Audio intelligence: https://developers.deepgram.com/docs/audio-intelligence and https://developers.deepgram.com/docs/stt-intelligence-feature-overview
- Flux quickstart: https://developers.deepgram.com/docs/flux/quickstart
- Flux compared with Nova-3: https://developers.deepgram.com/docs/flux/flux-nova-3-comparison
- Nova-3 to Flux migration: https://developers.deepgram.com/docs/flux/nova-3-migration
- Flux state machine: https://developers.deepgram.com/docs/flux/state
- Flux STT turn-detection parameters (the threshold table): https://developers.deepgram.com/docs/flux/configuration
- Nova-3 mid-stream
Configureand language hints: https://developers.deepgram.com/docs/configure, https://developers.deepgram.com/docs/nova-3-language-prompting - Flux control messages: https://developers.deepgram.com/docs/flux/configure, https://developers.deepgram.com/docs/flux/force-end-turn, https://developers.deepgram.com/docs/flux/close-stream
- Flux STT feature matrix (profanity filter, redaction scope, control messages): https://developers.deepgram.com/docs/flux/feature-overview
- Profanity filter, including Flux STT
language=multi: https://developers.deepgram.com/docs/profanity-filter - Bring your own turn detection (
eot_threshold=1.0plusForceEndTurn): https://developers.deepgram.com/docs/flux/own-turn-detection - Flux STT in a voice agent and eager end of turn (LLM call cost): https://developers.deepgram.com/docs/flux/agent and https://developers.deepgram.com/docs/flux/voice-agent-eager-eot
- Redaction, including the Flux STT
*placeholder: https://developers.deepgram.com/docs/redaction - Regional endpoints (EU, AU, India hosts for
/v1/listenand/v2/listen): https://developers.deepgram.com/reference/regional-endpoints - Numerals, including the Flux STT language list and mid-stream toggling: https://developers.deepgram.com/docs/numerals
- ForceEndTurn release note: https://developers.deepgram.com/changelog/2026/8/28
- Flux multilingual: https://developers.deepgram.com/docs/flux/language-prompting
- Authentication: https://developers.deepgram.com/guides/fundamentals/authenticating and https://developers.deepgram.com/guides/fundamentals/token-based-authentication
- Models endpoint: https://developers.deepgram.com/guides/fundamentals/model-metadata
- Error codes: https://developers.deepgram.com/docs/errors
- Voice Agent host (agent.deepgram.com): https://developers.deepgram.com/docs/build-a-voice-agent
- API reference: https://developers.deepgram.com/reference/speech-to-text/listen-pre-recorded, https://developers.deepgram.com/reference/speech-to-text/listen-streaming, https://developers.deepgram.com/reference/speech-to-text/listen-flux