Synthesize speech from text in any voice in your library — built-in or one you cloned. One request, POST /v1/audio/speech.

When to use it

Narration and long-form

Articles, chapters, courses. Split at 4,000 characters and stitch — the voice holds across requests because it resolves to the same clip.

Notifications and alerts

Short, repeated lines where the same voice every time matters more than anything else.

Anything a person waits on

Stream it. Time-to-first-audio is what reads as responsive; total synthesis time is not.

Prototyping a voice

Preview a clone before you commit it to a call — see Voices.

Quick start

The gateway accepts OpenAI’s full format list, but a model only serves the formats GET /v1/audio/models reports for it — asking nur-tts-v1 for opus is a 400, not a transcode.

Implementation details

Streaming

The response is chunked, so you can start playing before the whole body has landed rather than buffering the file first.
This streams the transfer, not the synthesis. A reply is generated as one piece, so nothing leaves the model until the utterance is finished — chunking saves you the download, not the generation. The way to shorten the wait is to synthesize less text per request. See Latency.
That is the default (stream_format: "audio") — raw bytes over a chunked response, which is the least work for an audio player. Set stream_format to "sse" instead if you want the same audio delivered as server-sent events, which is easier to multiplex with other messages on a single connection.

Sample rates

The backend emits 24 kHz mono PCM16. Telephony resamples to 8 kHz µ-law inside the pipeline — you don’t need to do it yourself.

Every generation is kept

Each request leaves a history entry, so a good take can be replayed and downloaded instead of regenerated. The response names the entry it created:
That header is exposed to browsers via CORS, so a web client can tie the bytes it just received to the row describing them — useful because the audio is uploaded to storage after the last chunk reaches you, and is briefly absent from the entry. Pass source to label where a request came from. It is free-form, and the platform’s own studio sends "playground":
List, replay and delete entries through /v1/generations:
An entry is written when the request is billed, so history and usage always agree. has_audio is false when retention is disabled for the deployment (SPEECH_GENERATION_HISTORY=false), when the upload failed, or in the moment before it completes — the entry is still a true record of what was said, so it is listed either way.

Going further

Voices

Why every voice needs reference audio.

Synthetic-audio marking

What every response declares about itself, and how to read it.