Public API v1

OpenAI-compatible speech synthesis

Drop-in for OpenAI POST /v1/audio/speech: point an OpenAI SDK at https://api.vieneu.io/api/v1 with your VieNeu key and it works unchanged. Returns the audio bytes directly — mp3 by default, like OpenAI; wav, opus and pcm are also available via response_format. Set stream_format to audio or sse to receive audio as it is generated instead of waiting for the whole file — that requires response_format: pcm or ulaw, the only two encodings whose frames concatenate. Maps input→text, voice→VieNeu voice id (from GET /v1/audio/voices) and model→engine. Billed by the submitted character count (minimum 50, × the AI surcharge only if you opt in with aiRefine: true) and refunded if synthesis fails. Auth via Authorization: Bearer <api key>.

post/api/v1/audio/speech

Request body

modelstring

Selects the engine. OpenAI model names (tts-1, tts-1-hd, gpt-4o-mini-tts) map to the default engine so an unmodified OpenAI client works; vieneu-v3 and vieneu-v4 select an engine explicitly. Any other value is accepted and ignored, as this endpoint has always done. A vieneu-… name for an engine that does not exist IS rejected — that is a choice of engine, and rendering on a different one would bill at a rate you did not pick. engine wins if both are sent.

inputstring required

The text to synthesize (OpenAI: input). Required.

voicestring

VieNeu voice id from GET /v1/voices (e.g. "Ngọc Lan"). Omit to use the default voice. (OpenAI voice names like "alloy" are not mapped — pass a VieNeu voice id.)

response_format'wav' | 'mp3' | 'opus' | 'pcm' | 'ulaw'

Output format. Defaults to mp3, as OpenAI does — a client that omits the field expects mp3, and returning WAV to it produced a file its player refused. wav, opus, pcm and ulaw are also supported; pcm is raw headerless signed 16-bit little-endian at 24 kHz — the rate OpenAI documents, and what this route defaults to unless sample_rate says otherwise — and ulaw is raw 8 kHz G.711 for telephony. OpenAI's aac and flac are not supported and return 400.

sample_rate8000 | 16000 | 22050 | 24000 | 44100 | 48000

VieNeu extension: output sample rate in Hz. Omit for 48000 — except with pcm, which defaults to 24000 (the rate OpenAI documents, since an OpenAI client has no field to ask for another and headerless PCM at the wrong rate plays at the wrong speed), and ulaw, which is always 8000.

speednumber

Playback rate, applied by a pitch-preserving time-stretch. OpenAI accepts 0.25–4.0 and so does this endpoint, but VieNeu's engine only holds quality across 0.5–2.0, so values outside that are CLAMPED, not rejected — a 400 for a value OpenAI itself considers valid would break the drop-in promise. The native /v1 endpoints validate 0.5–2.0 strictly instead.

instructionsstring

Accepted and ignored. It exists because gpt-4o-mini-tts — one of the model names this endpoint accepts — is the model whose whole point is this parameter, and the global validation pipe rejects unknown fields. Sending it must not 400; VieNeu conveys style through emotion and inline cues.

stream_format'audio' | 'sse'

Stream the response instead of buffering the whole file. audio sends the encoded bytes as they are produced (chunked transfer). sse sends OpenAI-shaped Server-Sent Events: speech.audio.delta carrying base64 audio, then a final speech.audio.done. That final event is the only positive proof the stream finished — without it, treat the audio as truncated. ONLY valid with response_format: pcm or ulaw: streamed frames are encoded independently, so mp3/opus/wav cannot be concatenated into one playable file and are rejected with 400. Note response_format defaults to mp3, so streaming requires setting it explicitly.

emotionstring

VieNeu extension: speaking style — 'natural' or 'storytelling'.

aiRefineboolean

VieNeu extension — 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.

engine'v3' | 'v4'

VieNeu extension: TTS engine — "v3" (48 kHz, default) or "v4" (48 kHz, premium). Omit for the configured default.

Example request

{
  "model": "tts-1",
  "input": "Xin chào, đây là VieNeu.",
  "voice": "Ngọc Lan",
  "response_format": "mp3",
  "sample_rate": 24000,
  "speed": 1,
  "instructions": "Speak in a calm tone.",
  "stream_format": "audio",
  "emotion": "natural",
  "engine": "v3"
}

Response

The audio bytes. Content-Type follows response_format (mp3 by default). With stream_format: "sse" the body is instead a text/event-stream of base64 audio deltas; with "audio" it is the same bytes, chunked. For the headerless pcm and ulaw formats the sample rate is in X-Sample-Rate (pcm defaults to 24 kHz here, not the engine native rate).

Changes

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