POST /v1/audio/speech returns the whole take when it is done. For long text that means waiting for the last word before you have the first byte — and holding the entire file in memory while you wait. Stream it instead: write each chunk as it arrives.

Prerequisites

Create one in Settings → API keys, or see Get your API key. Keep it server-side — a key grants full access to your organization.
Any voice_id from GET /v1/voices. Built-in voices work; so does one you cloned.

Recipe

timeout=None matters. A long chapter can take longer than a default client timeout, and the request will be cut mid-synthesis — you will have paid for audio you did not keep.

Text longer than one request

A single request takes up to 4,000 characters. Split on sentence boundaries, not mid-word, and concatenate the parts. The voice does not drift between them. Every voice resolves to the same stored reference clip on every request, so part twelve sounds like part one — see Voices.
Concatenate the decoded audio, not the encoded files. Joining two MP3s byte-wise produces a stream most players will play and some will not, and the seam is audible. Decode each part, join the samples, encode once.

Server-sent events instead

Set stream_format: "sse" to receive the same audio as server-sent events rather than raw bytes. Reach for it when the audio shares a connection with other messages; for writing a file, raw bytes are less work.

Going further

Text to speech

Every field on the endpoint.

Voices

Cloning, and why a voice holds across requests.