Public API v1

Stream speech synthesis with low latency

Streams audio as it is generated so playback can start within ~1–2s instead of waiting for the whole text. The response is a binary stream (Content-Type: application/octet-stream) of length-prefixed frames: repeat { read a 4-byte big-endian uint32 = N, then read N bytes = one audio frame } until EOF. A COMPLETE stream ends with a zero-length frame (N = 0) — if it is missing, the stream was cut short and you should discard the audio; it is not billed. Each frame is a self-contained WAV by default; pass outputFormat for raw headerless pcm/ulaw to feed a telephony or voice-agent pipeline, or mp3/opus to cut bandwidth. DECODE EACH FRAME SEPARATELY — frames are encoded independently, so concatenating mp3 or opus frames produces gaps and clicks; only pcm/ulaw can simply be joined. The actual sample rate is in X-Sample-Rate, the encoding in X-Output-Format, the framing in X-Stream-Format. PRICE: the same per-character rate as POST /v1/tts, but every stream runs on the v4 engine and is therefore charged at the v4 engine multiplier — higher than the v3 one. Sizing a budget with POST /v1/tts on v3 and then streaming the same text will cost more; GET /v1/engines returns the live multipliers. (+ the AI surcharge only if you opt in with aiRefine: true, which also moderates and normalizes the text first.) voiceId accepts a preset or one of your own cloned voices (clone_… from POST /v1/voices) — a clone costs exactly what a preset costs on the engine you name; cloning adds no surcharge of its own. Note the engine you name is the engine that renders: a clone is NOT currently checked against the engine it was enrolled on. Clones have enrolled on v4 since 2026-08-28, so for those the two always agree; an older v3-enrolled clone named with v4 will render on v4 from a v3 reference clip and will not sound like the intended voice. Re-enrol it instead.

post/api/v1/tts/stream

Request body

textstring required

Vietnamese text to synthesize and stream.

voiceIdstring

Voice ID from GET /v1/voices: a preset, or one of your own cloned voices (clone_…, created with POST /v1/voices — an admin-published clone works too). A voice is only usable on the engine it belongs to. Omit to use the default voice.

emotion'natural' | 'storytelling' | 'tin_tuc' | 'tu_nhien' | 'doc_truyen' | 'emotion_0' | 'emotion_1' | 'emotion_2' | 'emotion_3' | 'emotion_4' | 'emotion_5' | 'emotion_6' | 'emotion_7' | 'emotion_8' | 'emotion_9' | 'emotion_10' | 'emotion_11' | 'emotion_12' | 'emotion_13' | 'emotion_14' | 'emotion_15' | 'emotion_16' | 'emotion_17' | 'emotion_18' | 'emotion_19'
speednumber

Playback speed (0.5–2.0).

engine'v4'

Streaming runs on v4 only — v3 is rejected here. You may omit this: v4 is the default engine. NOTE ON PRICE: because every stream runs on v4, it is charged at the v4 engine multiplier, which is higher than the v3 one. If you priced your workload with POST /v1/tts on v3, streaming the same text will cost more. GET /v1/engines returns the live multipliers.

aiRefineboolean

AI text refinement. Defaults to FALSE on the public API: the text is synthesized as submitted, with no AI moderation and no pronunciation normalization, billed at the plain per-character rate. Set true to run the same AI step the web app uses — formulas, acronyms and mixed-in English are read correctly and the content is checked — billed with the AI surcharge and one extra model round-trip of latency. Deterministic text preparation is applied either way.

outputFormat'wav' | 'mp3' | 'opus' | 'pcm' | 'ulaw'

Encoding of the audio inside each frame. wav (default) keeps every frame self-contained and is what existing clients expect. mp3 and opus cut bandwidth roughly six-fold. pcm and ulaw are HEADERLESS raw audio for telephony and voice-agent pipelines — read the rate from the X-Sample-Rate response header. The frame FRAMING is unchanged in every case, so the end-of-stream marker still means the same thing.

sampleRate8000 | 16000 | 22050 | 24000 | 44100 | 48000

Output sample rate in Hz. Omit for the engine native rate (48000). opus is always 48000 and ulaw always 8000 — passing a conflicting value is rejected rather than quietly ignored.

Example request

{
  "text": "Xin chào Việt Nam!",
  "voiceId": "Ngọc Lan",
  "emotion": "natural",
  "speed": 1,
  "engine": "v4",
  "outputFormat": "wav",
  "sampleRate": 24000
}

Response

A binary stream of length-prefixed frames: repeat { 4-byte big-endian uint32 N, then N bytes }. A COMPLETE stream ends with N = 0; without that marker the audio was cut short — discard it (it is not billed). X-Sample-Rate, X-Output-Format and X-Stream-Format describe the frames.

Changes

No recorded changes to this endpoint across all 1 revision of this API.