Skip to content

Streaming audio

Play streamed audio, save WAV files, and handle interruptions.

POST /v1/audio/speech streams audio bytes. Read the response incrementally; its total length is unknown when streaming begins.

Text input in a voice agent

Each request accepts one complete input string. Streaming applies to the audio response; this endpoint does not accept an ongoing text stream over WebSocket.

When your LLM emits text incrementally, let your agent framework group it into suitable phrases before sending speech requests. Very short fragments can interrupt the rhythm of the spoken reply; waiting for the entire answer can delay it. Test that tradeoff with your own dialogue. The LiveKit configuration uses the framework's existing text segmentation and playback.

If the caller interrupts, stop playback and cancel the active synthesis through your framework. Cancellation does not undo audio already delivered or its charge; see interruptions and billing.

Audio formats

response_formatContent typeAudio
pcm (default)audio/pcmSigned 16-bit little-endian PCM, mono, without a header.
wavaudio/wavThe same PCM with a 44-byte WAV header.

The default sample rate is 24,000 Hz; sample_rate accepts 8,000–48,000 Hz. Set response_format explicitly when using an SDK that defaults to another format.

Response headers

HeaderMeaning
Content-TypeAudio format, or application/json for errors before streaming.
X-Sample-RateEffective sample rate in Hz.
X-Channels1 for mono.
X-Request-IdID for operation status and support.
Cache-Controlno-store.

X-Audio-Sample-Rate and X-Audio-Channels contain the same values as their shorter equivalents.

Playing raw PCM

Configure your player for signed 16-bit little-endian mono audio at X-Sample-Rate. Network chunks can split a two-byte sample: keep any final odd byte and prepend it to the next chunk. A small playback buffer helps absorb network jitter.

Playing streaming WAV (audio/wav)

The first 44 bytes are the WAV header; they may arrive across several network chunks. Both length fields use 0xFFFFFFFF because the final size is not yet known. Use a streaming-aware player.

After verifying completion, finalize the file saved in the Quickstart with FFmpeg:

ffmpeg -i speech.partial.wav -c:a copy speech-final.wav

This updates the header without re-encoding the audio. To finalize it in your own code:

  1. Calculate data_bytes = file_size - 44.
  2. Write data_bytes + 36 at byte offset 4 as a 32-bit little-endian integer.
  3. Write data_bytes at byte offset 40 in the same format.

For a playable file with completion checks, use the Python quickstart. The agent skill creates finalized WAV files; verify the recording before using it.

Interruptions and billing

  • Speech is charged for its full input text once audio is delivered, including partial streams and cancellations.
  • Requests delivering no audio are not charged. A WAV header alone does not count as audio.
  • Charges settle when the operation ends, which may be after a disconnect.

Failures before streaming return a JSON error. Failures after headers interrupt the stream, so HTTP 200 alone does not prove completion.

Save X-Request-Id, keep interrupted audio marked as partial, and check operation status before retrying. A completed operation reports completion_bytes; compare it with received PCM bytes, excluding the WAV header. Save API audio in your application. The saved-recording API can retrieve only recordings that were successfully saved; it cannot recover an unsaved recording, and an interrupted response does not guarantee that a complete recording exists.