Streaming
Two WebSocket endpoints for when a round trip is too slow: push text in as it is generated, or push audio in as it is spoken.
When to use it
The REST endpoints already stream their response. Reach for WebSocket when you also need to stream the request: piping LLM tokens into speech before the sentence is complete, or transcribing a live microphone. For batch jobs, REST is simpler and just as fast.
Endpoints
wss://api.quickdial.ai/v1/tts/stream wss://api.quickdial.ai/v1/stt/stream
Authenticate with the same bearer key. Browsers cannot set headers on a WebSocket handshake, so the key may instead be passed as a query parameter, but only ever from a server or a short-lived proxy token, never from client-side code holding your live key.
# preferred, from a server Authorization: Bearer $QUICKVOICE_KEY # fallback where headers are impossible wss://api.quickdial.ai/v1/tts/stream?key=qtts_live_xxxxxxxx
Text to speech
Send JSON text frames; receive binary audio frames. Send a flush message to force
generation of everything buffered so far, and close when the utterance is finished.
{ "type": "start", "voice": "azelma", "format": "opus" }
{ "type": "text", "value": "Your table is " }
{ "type": "text", "value": "confirmed for eight." }
{ "type": "flush" }
{ "type": "close" } import WebSocket from "ws"; const ws = new WebSocket("wss://api.quickdial.ai/v1/tts/stream", { headers: { Authorization: `Bearer ${process.env.QUICKVOICE_KEY}` }, }); ws.on("open", () => { ws.send(JSON.stringify({ type: "start", voice: "azelma" })); // pipe tokens straight from your model as they arrive for (const token of tokens) { ws.send(JSON.stringify({ type: "text", value: token })); } ws.send(JSON.stringify({ type: "close" })); }); ws.on("message", (frame, isBinary) => { if (isBinary) speaker.write(frame); // audio chunk else console.log(JSON.parse(frame)); // status / usage });
Speech to text
Send binary audio frames; receive JSON transcript frames. Partial results arrive continuously and are
replaced as context improves. Render partial optimistically, then commit on
final.
{ "type": "partial", "text": "I found three" }
{ "type": "partial", "text": "I found three matching options" }
{ "type": "final", "text": "I found three options that match your request.",
"words": [ { "word": "I", "start_ms": 40, "end_ms": 210 } ] } Expected audio
- 16-bit signed PCM, mono.
- 16 kHz sample rate.
- Frames of roughly 20–100 ms. Smaller frames lower latency but raise overhead.
Backpressure and reconnects
- Watch the socket's buffered amount before sending more. If it grows, the network is the bottleneck, not the API.
- Idle sockets close after 60 seconds without a frame. Send a WebSocket ping to hold one open between utterances.
- Reconnect with exponential backoff starting around 500 ms. A dropped socket never loses billing state; usage is recorded per completed request.
- An
errorframe arrives before the close for anything actionable. See Errors & limits.