DocsDeveloper

Realtime Speech to Text

Live transcription over a WebSocket: mint a short-lived token, stream fixed-format PCM, read partials and finals as they stabilise.

Almost none of this endpoint is HTTP: POST /api/v1/speech-to-text/stream/token is the only request, and everything after happens on a WebSocket straight to the transcription engine. A token is good for one streaming session and expires 600 seconds after minting — that is also the longest a single session may run, so long recordings re-mint and reconnect. The audio contract is fixed: raw 16-bit little-endian PCM (pcm_s16le), 16,000 Hz sample rate, one channel, sent as binary WebSocket frames — no WAV header, no other rate, no stereo. The mint response repeats the contract (audio_format, sample_rate, channels) so your client can assert it rather than assume it.

Authentication

The token mint takes your account API key (sv-api-key) with the stt:transcribe scope, on a plan that includes realtime speech-to-text — Creator and up today; without it the mint answers 403 plan_limit_exceeded. The WebSocket itself never sees your API key: connect with the minted token, either as an Authorization: Bearer header or — for browsers, which cannot set WebSocket headers — as ?token= on the URL.

Create a key in Settings → API Keys. It is shown once, so copy it then. Every example below reads it from $SONICVOX_API_KEY.

Endpoints

POST/api/v1/speech-to-text/stream/tokenFull reference →

Mint a streaming session. The optional body { "language": "en" } sets a language hint (also settable over the socket with a config message). The response names the wsUrl to connect to, the token, and its unix-seconds expiresAt. Billing is settled, not flat: one minute of transcription is reserved at mint as an affordability check — sized against your plan's included STT hours, so reserved_credits is 0 when your allowance covers it — and when the stream ends the engine reports the real duration and the session settles to it: unused reserve refunded, extra time charged.

Scope
stt:transcribe
Credits
1-minute reserve at mint (0 if plan STT hours cover it); settled to real duration — 300/min beyond included hours
curl https://staging.sonicvox.ai/api/v1/speech-to-text/stream/token \
  -X POST \
  -H "sv-api-key: $SONICVOX_API_KEY" \
  -H "content-type: application/json" \
  -d '{"language": "en"}'

# 503 service_unavailable here means realtime is not yet enabled in this
# environment (see the availability note) — nothing was charged.
Response
{
  "wsUrl": "wss://<engine-host>/stream",
  "token": "t:<user>:<expiry>:<nonce>:<hmac>",
  "expiresAt": 1793476800,
  "language": "en",
  "reserved_credits": 300,
  "audio_format": "pcm_s16le",
  "sample_rate": 16000,
  "channels": 1
}

# Then, on the socket —
# client → server (binary): raw pcm_s16le 16 kHz mono frames
# client → server (text):   {"type":"config","language":"en"}
#                           {"type":"flush"}   {"type":"close"}
# server → client (text):   {"type":"partial","text":"..."}
#                           {"type":"final","text":"...",
#                            "start":0.32,"end":1.78,"confidence":0.94}
#                           {"type":"error","message":"..."}

When it fails

Every error carries type, code, message, request_id and a doc_url. Branch on type for retry policy.

service_unavailableRealtime capacity is not yet switched on for this environment — the mint fails CLOSED rather than handing out a socket that cannot connect, and nothing is charged. This is the rollout state, not a fault in your request.
plan_limit_exceededThe plan does not include realtime speech-to-text (it starts on Creator), or does not include API access at all.
insufficient_creditsThe 1-minute reserve could not be taken. No session started and nothing was charged.
account_limitedTemporary throttle after repeated content-policy violations. It clears on its own; retrying extends it.
Every error code →

Next

Was this page helpful?
Realtime Speech to Text | SonicVox Docs