Skip to main content
Control messages are JSON in text WebSocket messages, each with a type. Audio goes in binary messages. The server only sends text messages. Ignore fields you don’t recognise: messages may gain fields over time.

start

Opens the session. Send it as the first message, within 10 seconds of connecting.
The avatar’s video and voice stream to your users’ browsers over WebRTC.
string
required
"start"
string
required
Your tav_… API key.
string
required
An avatar ID, such as ava4. See Avatars.
integer
default:"24000"
Your audio’s sample rate: 8000, 12000, 16000, 24000 or 48000.
string
"direct" for direct output to browsers. Leave it out for LiveKit.
string
LiveKit only: your LiveKit server’s URL.
string
LiveKit only: the publish-only token you minted for the avatar’s participant.
object
LiveKit only. Direct output always plays the voice.

ready

The avatar is live and billing has started. Send audio only after it.
integer
The video width in pixels
integer
The video height in pixels
boolean
true when the avatar plays the voice (direct output, or LiveKit with audio.publish)
Starting can take a few seconds while the avatar’s stream is set up.

Audio

Your agent’s voice, as it streams. Each binary message is a 12-byte header followed by audio:
  • Send audio as it’s generated. It can arrive faster than real time: it’s queued and spoken at its natural pace.
  • Queueing: audio with play time 0 plays right after the audio already queued, or about 400 ms after it arrives when nothing is queued.
  • Chunks of any length, as long as each message holds whole samples and stays under 1 MB. If your TTS splits a sample across chunks, carry the odd byte over to the next message.
  • Raw PCM only. Decode MP3, Opus or WAV first, and strip WAV headers. See Stream audio for provider settings.
  • Don’t play the audio yourself when the avatar plays the voice: users would hear it twice.

Play times

Only when you play the voice yourself (LiveKit without audio.publish): set the play time to the wall-clock moment, in milliseconds since the Unix epoch, when the first sample of this message will be heard. Send audio about 400 ms ahead of its play time, so the avatar’s lips can be ready, and keep your server’s clock synchronised (NTP).

clear

The user interrupted: drop the audio that hasn’t played yet, and stop the avatar mid-sentence.
When the avatar plays the voice, the reply says how many milliseconds of the interrupted reply the user heard, so you can truncate your agent’s transcript:
There’s no reply when you play the voice yourself.

Speech events

Sent when the avatar plays the voice.
A reply’s first audio is playing.
Everything queued has played. playedMs is how much of this reply was heard.

view

Direct output only. A browser wants to watch: ask for a WebRTC offer for it. Give each request an id of your choice; the reply carries the same id.
string
This viewer’s ID, for its answer
string
The WebRTC offer, for the browser’s setRemoteDescription({ type: "offer", sdp })

view_answer

The browser’s answer to the offer.
The browser then receives the avatar’s video and voice. Run view and view_answer once for every browser, and again whenever a browser reconnects. See Browser playback. A failed view or view_answer gets an error with the request’s id, and the session carries on.

republished

Direct output only. The stream dropped and has recovered on a new connection:
Browsers must watch again: run the view handshake for each one. (The SDK’s LiveAvatarView notices on its own.) If the stream can’t recover, the connection closes with 1011.

error

Something went wrong.