API reference

Create a stream session

The one HTTPS call: exchange your API key for a socket to open.

Post the session you want and receive a socket to open. This is the only HTTPS call in the speech API, and the only place your key is ever sent.

POSThttps://api.zeroweight.ai/api/v1/realtime/stream/session

Authentication#

X-ZW-Api-Key: your-api-key. Not Authorization: a bearer token there is an anonymous request as far as this route is concerned.

Request body#

Every field here becomes a query parameter on the socket, which is another way of saying every field is fixed for the life of the connection.

voice_idstringoptional
A built-in voice, a system voice, or one you cloned. Omitted, the gateway picks its default. See Voices.
formatstringoptionaldefault "pcm_s16le"
Wire format of the audio frames.
sample_rateintegeroptionaldefault 24000
8000–48000. Ask for it explicitly: a player built at one rate against a stream at another is silently wrong rather than broken.
normalize_textbooleanoptionaldefault true
Expand digits, dates, times and acronyms into the words a speaker would say. Turn it off if you normalize your own text, because expansion is not idempotent.
chunk_secondsnumberoptionaldefault 15
The segmenter’s duration budget.
samplingobjectoptional
Optional sampling knobs; see the table. An unknown name is answered with 422 here rather than dropped silently downstream.
inputstringoptional
Text to speak. A convenience: it does not travel on the URL, and supplying it makes the response carry the exact frames to send, so a caller can open the socket and write them without knowing the protocol. Omit it to drive the session yourself, which is what a voice agent streaming a language model’s output wants.
context_idstringoptionaldefault "turn-1"
Names the queue that input is synthesised on.

Response#

urlstringrequired
A wss:// URL, ready to open. It carries a short-lived token, not your key.
expires_in_secondsintegeroptional
How long the URL stays usable, about thirty seconds. It does not bound the session; once the socket is open it lives until something closes it.
max_concurrent_sessionsintegeroptional
What this plan may hold open at once, so your own queue does not need a copy of our plan table.
gatewaystringrequired
Which deployment answered. Quote it in a support request.
protocolstringrequired
"zerotts.v1", the message protocol spoken on the socket.
voice_id / format / sample_ratemixedrequired
Echoed back resolved, not as asked for. A default you did not send is exactly the value you most need told, and sample_rate decides how you must build your player.
messagesarrayrequired
JSON frames to send in order once the socket opens. Empty unless input was given.

Example#

curl -X POST https://api.zeroweight.ai/api/v1/realtime/stream/session \
  -H "X-ZW-Api-Key: $ZEROWEIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "voice_id": "maichi",
    "format": "pcm_s16le",
    "sample_rate": 24000,
    "normalize_text": true
  }'
200 OKjson
{
  "url": "wss://tts-gateway-prod.example/v1/stream?token=zwst_1…&voice_id=maichi&format=pcm_s16le&sample_rate=24000",
  "expires_in_seconds": 30,
  "expires_at": "2026-09-13T04:21:07Z",
  "max_concurrent_sessions": 8,
  "gateway": "tts-gateway-prod",
  "protocol": "zerotts.v1",
  "voice_id": "maichi",
  "format": "pcm_s16le",
  "sample_rate": 24000,
  "messages": []
}

Using input#

Supply input and the response comes back with the frames already written for you. Useful for a one-shot utterance; not what you want for a conversation, where a take can be cancelled mid-stream and text arrives a sentence at a time.

// request
{ "voice_id": "maichi", "input": "Xin chào.", "context_id": "turn-1" }

// response, abbreviated
{
  "url": "wss://…",
  "messages": [
    { "type": "synthesize", "context_id": "turn-1", "text": "Xin chào.", "segment_mode": "auto" },
    { "type": "end", "context_id": "turn-1" }
  ]
}

Errors#

StatusMeaning
401The key is wrong, revoked or absent.
402No API plan on the account, or out of credits.
422An unknown sampling parameter. The body names it.
429Rate limited.
503The gateway is unreachable or not configured. Ours; retry.

Capacity and voice entitlement are not checked here. The gateway owns the concurrency lease and the voice, so a 200 from this route can still be followed by a close code on the socket.