Public API v1

Stream speech synthesis with low latency

Changed on

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_…, created in the web Studio at https://vieneu.io/#/clone) — 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

  • Base URL
    https://api.vieneu.io
  • Auth
    • API key in header X-API-Key
    • or HTTP bearer

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 in the web Studio at https://vieneu.io/#/clone — an admin-published clone works too). A preset may also be given by its display name (name). 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, the default and only engine. You may omit this. GET /v1/engines returns the live billing multiplier.

aiRefineboolean

AI text refinement. Defaults to FALSE on the public API: the text is synthesized as submitted, with no AI moderation and no AI 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, and so is your pronunciation dictionary (see applyPronunciation).

applyPronunciationboolean

Read the text through your account's pronunciation dictionary — the rules saved at https://vieneu.io/#/pronunciation (Từ điển phát âm). Defaults to TRUE, and changes nothing until you have saved rules there. The rules run after aiRefine and before synthesis; you are billed for the text you sent, and that is the text kept with the job. Set false to read this request as written. If your rules make the text longer than the request limit, or more than twice as long plus 1,000 characters, the call is refused with 400 PRONUNCIATION_EXPANDED_TOO_LONG, uncharged.

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",
  "applyPronunciation": true,
  "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

    • info

      added the new optional request property

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status