STT selection for narrowband (8kHz μ-law) inbound telephony. Deepgram Flux is the pick — but the more important finding is that every published streaming-STT leaderboard is measured on audio a phone trunk will never deliver.
Deepgram Flux — The Pick
flux-general-en, endpoint wss://api.deepgram.com/v2/listen.
Note the
/v2— Flux is not on/v1This trips up SDK integration. Everything else in the Deepgram surface (Nova-2, Nova-3) is
/v1/listen. Flux is a v2 endpoint.
Why it wins
- Fused end-of-turn detection. Flux folds EOT detection into the acoustic model itself rather than bolting a separate VAD on top. ~260ms EOT p50.
- Native
encoding=mulaw&sample_rate=8000. Twilio Media Streams frames go in with zero transcoding — no resample, no format conversion, no added buffer. This is a latency and a code-complexity win. EagerEndOfTurn/TurnResumedevent pair. Fires 150–250ms before confirmed EOT.- The only first-party Rust SDK in the entire field. Crate
deepgramv0.10.0, published 2026-07-12. Deepgram also publishes a Twilio↔Rust streaming tutorial. For a Rust-native build where every other vendor is Python/Node-first, this is a real advantage.
Flux tail is long — p50 is not the story
Percentile EOT latency p50 ~260ms p90 ~1,000ms p95 ~1,500ms This is consistent with the general finding that every platform roughly triples p50→p95. Budget against p95.
Speculative LLM dispatch
Use
EagerEndOfTurnto hide LLM TTFTDispatch the LLM on
EagerEndOfTurn; cancel onTurnResumed. This buys back 150–250ms of the ~270ms LLM TTFT.Cost: 50–70% additional LLM calls. At Haiku 4.5 prices with prompt caching (~$0.0032/min, ~10% of total cost) this is trivially worth it — a 70% increase on 10% of cost is a ~7% cost increase for a ~200ms latency win. See voice-agent-cost-model-2026-07-21.
Tuning knobs
| Parameter | Range | Default |
|---|---|---|
eot_threshold | 0.5 – 0.9 | 0.7 |
eager_eot_threshold | 0.3 – 0.9 | — |
eot_timeout_ms | 500 – 60,000 | — |
Lower eot_threshold = faster commit, more mid-sentence cut-offs. For a receptionist taking phone numbers and addresses this needs to be context-dependent — the digit-string case is exactly the [[voice-agent-managed-platform-control-surfaces-2026-07-21#the-onnumberseconds-gap|onNumberSeconds problem]] that only two managed platforms solve, and which owning the pipeline lets you solve properly.
Verify before building
[unverified] whether the
deepgramRust crate v0.10.0 covers/v2/listen(Flux) or only/v1. The crate is the headline reason to prefer Deepgram in a Rust build; if it’s v1-only, that advantage partly evaporates and you’re hand-rolling the WebSocket client anyway.
AssemblyAI Universal-Streaming — Cheaper, But Slow to Commit
| Property | Value |
|---|---|
| Price | $0.0025/min — cheaper than Flux |
| Word emission P50 | 307ms |
max_turn_silence default | 1,280ms |
~5x slower than Flux to commit a turn
Word emission latency (307ms) looks competitive, but that’s words appearing, not the turn being committed. The 1,280ms default
max_turn_silencemeans the agent waits over a second of silence before deciding the caller is done. That is past the ~800ms “unnatural” threshold on its own, before the LLM has even started.
Billing gotcha — bills by SESSION duration, not audio duration
AssemblyAI bills the wall-clock length of the WebSocket session, not the amount of audio you send. For telephony, where the connection stays open across long silences and hold periods, this makes the headline $0.0025/min misleading. Model it against real call duration, not real speech duration.
Critical Benchmark Caveat
Artificial Analysis' streaming STT index contains NO narrowband telephony audio at all
Composition of the index:
- 50% AA-AgentTalk
- 25% VoxPopuli (European Parliament recordings)
- 25% Earnings22 (earnings calls)
All wideband. Every published leaderboard position is measured on audio a G.711 trunk will never deliver. Narrowband 8kHz μ-law drops everything above ~3.4kHz and adds companding noise — the exact band where fricative and sibilant discrimination lives (
s/f,p/t/k). This is where telephony WER diverges from benchmark WER, and it’s the band that matters most for names, emails, and spelled-out strings.
Nobody publishes per-domain telephony WER
This is a genuine gap in the public record, not an oversight in the research. There is no leaderboard that answers “which STT is best on 8kHz μ-law.”
The required mitigation
Budget a week for an own A/B on real trunk audio
Record 8kHz μ-law directly off the actual Twilio trunk — not resampled studio audio, not a synthetic downsample. Then A/B candidate models on it.
Use Deepgram Nova-2
phonecallas the control. It is the only model in the field explicitly special-cased for narrowband. If Flux can’t beat Nova-2phonecallon real trunk audio, the fused-EOT advantage isn’t paying for the accuracy loss.Weight the test set toward the failure modes that matter for a receptionist: names, email addresses, phone numbers, booking references, spelled-out alphanumerics. These are the same categories that kill speech-to-speech models and they will be the weakest part of any cascade too.
This is open item #6 in voice-agent and the highest-value one — it’s the only item that could change the vendor decision.
Decision Summary
| Deepgram Flux | AssemblyAI Universal-Streaming | Deepgram Nova-2 phonecall | |
|---|---|---|---|
| Turn commit | ~260ms p50 | ~1,280ms default | n/a (external VAD) |
| Native μ-law 8k | yes | — | yes, tuned for it |
| Rust SDK | first-party | — | first-party |
| Speculative dispatch | EagerEndOfTurn | — | — |
| Price | $0.0065/min | $0.0025/min (session-billed) | — |
| Role | primary | rejected on commit latency | A/B control |
Sources
- Deepgram Flux docs — endpoint, encoding,
EagerEndOfTurn, tuning params [vendor] - Deepgram Rust crate v0.10.0, published 2026-07-12 [vendor]
- Deepgram Twilio↔Rust streaming tutorial [vendor]
- AssemblyAI Universal-Streaming docs —
max_turn_silence, session billing [vendor] - Artificial Analysis streaming STT index — dataset composition [measured, but wideband-only]