API Reference
Connection
| Field | Value |
|---|---|
| Endpoint | wss://api.denthub.ai/stt/realtime/stream |
| Query | ?key=<key> |
| Audio | PCM16LE · 16000 Hz · mono · binary frames |
| Max conns/pod | 200 (HTTP 503 when exceeded) |
start↑ first frame (text)
| Field | Type | Required | Value |
|---|---|---|---|
| type | string | yes | "start" |
| sample_rate | int | yes | 16000 |
| codec | string | yes | "pcm_s16le" |
| channels | int | yes | 1 |
audio↑ binary frames
Send raw PCM16LE bytes as binary WebSocket frames — no WAV header, no base64, no JSON wrapping. Any frame size works; send continuously, without gating on silence yourself.
The gateway re-frames your stream internally into 32 ms VAD windows and detects utterance boundaries server-side, so you never need to run your own voice-activity detection.
end↑ graceful close (text)
Send this text frame to flush any pending utterance and close cleanly. After sending it, you may close the WebSocket yourself, or wait for the server to close it once flushing finishes.
{ "type": "end" }result↓ one per utterance
{
"type": "result",
"utt_index": 0,
"session_id": "b1f7…",
"abs_start_utc": "2026-07-10T05:12:01.80Z",
"abs_end_utc": "2026-07-10T05:12:05.20Z",
"duration_ms": 3400,
"text": "Patient presents with sensitivity on the upper right quadrant.",
"segments": [
{ "start_ms": 800, "end_ms": 4200,
"text": "Patient presents with sensitivity…", "language": "en" }
],
"words": [ { "word": "Patient", "start_ms": 800, "end_ms": 1180 }, … ],
"status": "ok",
"forced_cut": false,
"continues": false
}| Field | Type | Description |
|---|---|---|
| utt_index | int | 0-based, monotonic per connection |
| session_id | uuid | Connection session ID |
| abs_start_utc / abs_end_utc | string (ISO 8601) | Absolute utterance start/end (UTC) |
| duration_ms | int | Utterance duration (sample-derived) |
| text | string | Full transcription text |
| segments[] | array | start_ms / end_ms / text / language, recording-relative |
| words[] | array | word / start_ms / end_ms, recording-relative |
| status | string | "ok" · "empty" · "failed" |
| forced_cut | bool | true if the utterance was force-split at max length |
| continues | bool | true if the next utt_index continues this utterance |
Every timestamp here —
abs_*_utc, and each start_ms/end_ms inside segments[] and words[] — is recording-relative, derived from a sample-count clock, not message-arrival time. Use these to line results up against the audio you sent, even under network jitter.↓ session · warning · error
{"type":"session","event":"started","session_id":"…"} // started · ended
{"type":"warning","code":"SLOW_CONSUMER"} // backpressure
{"type":"utterance_dropped","utt_index":8,"code":"STT_OVERLOAD"}
{"type":"error","utt_index":9,"code":"STT_TIMEOUT","message":"…","retryable":true}- session — connection lifecycle:
startedandended. - warning — backpressure signal (
SLOW_CONSUMER): you're sending audio faster than the gateway can process; slow down or check your network. - utterance_dropped — the STT backend was overloaded and this utterance was skipped; the gap in
utt_indextells you which one. - error — a per-utterance failure; check
retryableto decide whether to wait or move on.
Close codes
| Code | Meaning |
|---|---|
| 1000 | Normal close, after you sent end |
| 1001 | Going away — server is draining; reconnect to a new session |
| 1011 | Internal error — log it and reconnect |