Skip to main content
This page documents the LTX wire surface: every command you send, every message the model emits back, and a complete example. For a general understanding of LTX and a quick start, see the overview.

The session model

A take is generated from the conditions as they stood at start. Every set_* command stays valid while a take runs, but a mid-run change applies to the next take, never the current one. The model lists each queued field in state_update.queued_changes. start is the one exception: it is rejected while a take is running, so wait for that take to end before beginning the next. state_update.valid_commands is the authoritative list of what the session would accept right now. Drive your UI from it; any command not listed comes back as command_error.

Commands

Send commands with reactor.sendCommand() (base SDK) or the typed methods (typed SDK). All available commands:

set_avatar_image

Provide the still image that defines the avatar’s identity, framing, and background for the whole take. Required before calling start. The image is fitted to the 16:9 generation canvas (640×352), so a tall portrait gets its top cropped off by that fit; crop to the frame before uploading. On success the model emits avatar_image_accepted with the decoded dimensions and a state_update where has_avatar_image is true; an unreadable file returns command_error. Parameters:
Use a clear, well-lit photo of one person facing the camera, framed so the whole head is visible. A low-quality, occluded, or profile photo degrades the whole take, and a photo with multiple people is undefined as to which becomes the avatar.

set_script

Set the words the avatar speaks. Required before calling start. Unless an explicit duration is set, the take’s length is the script’s word count divided by the session’s words-per-minute pace. The script is read once at start and cannot change part-way through a take. On success the model emits script_accepted carrying the word count and the take’s derived length (derived_seconds); a blank script returns command_error. Parameters:
Natural punctuation produces natural pauses. ALL-CAPS or emoji-heavy scripts are spoken literally or render garbled.

set_prompt

Describe the voice, the staging, and the delivery: register and accent, lighting, mood, and energy. The model generates audio and video in one pass and conditions both on this prompt, so it is where the voice is cast as well as the shot. This is not necessary before sending start. If left blank, the prompt defaults to a straight-to-camera talking head, and sending an empty string restores that default. The prompt is read once at start and applies to the whole take. set_prompt does not control identity or wardrobe, which are anchored to the avatar image. Resending it re-casts the voice, so a character that has been speaking across several takes comes back sounding like someone else; set it once and pin set_seed for the same reason. See the prompt guide for how to write one. Parameters:

set_wpm

Override the speaking pace in words per minute. Accepts 80–220; the default is 140. The pace lays the script out over the take and sets its derived length. This controls how fast the script is spoken, not video playback speed. Out-of-range values are rejected with command_error, unlike set_duration_seconds, which clamps. That 80–220 range can differ between deployments, so read wpm_min/wpm_max off state_update rather than hard-coding it. On success the model emits wpm_accepted carrying the take’s recomputed length. Parameters:

set_duration_seconds

Set an explicit take length in seconds. When duration_seconds is zero, the length goes back to being derived from the script at the session’s pacing. Out-of-range values clamp to the deployment’s 4–300 second range, unlike set_wpm, which rejects. state_update.effective_seconds reports the length the next take will actually have, whichever way it was determined. If the requested duration exceeds what the script needs at the current pace, the avatar continues in an idle presence for the remainder; it does not loop or extend the script. Parameters:

set_seed

Set the seed for the next take. The same conditions with the same seed reproduce the same take. Reproducibility holds within one deployed build; a new release can change what a given seed produces. Parameters:
Use set_seed to generate variations on the same setup. Keep the seed to get the same take again, change it for a different take from the same image, script, and settings.

start

Begin generating a take. Requires an avatar image and a script; state_update.ready reports when both are set. Emits generation_started, then one window_progress for each window it streams. Returns command_error if a condition is missing or a take is already in flight.

pause

Freeze the output stream mid-take on its current frame. Generation keeps running ahead into a bounded buffer, so resume continues instantly. Emits generation_paused. Returns command_error if no take is in flight or it is already paused.
Pausing does not reduce what you pay. Billing is per session-second for as long as the GPU is held for you, so a paused take costs the same as a running one. See Pricing & Billing.

resume

Continue a paused stream exactly where it froze, with no warm-up. Emits generation_resumed. Returns command_error if the stream is not paused.

stop

End the take in flight within about a second, keeping every condition (image, script, and settings) so start immediately begins a fresh take with the same setup. Emits generation_stopped. Returns command_error if nothing is in flight. To end a take and clear the conditions, use reset.

reset

Return every condition to its default and the model to waiting for new ones. This is the only way to clear the avatar image. Valid at any time; during a take it also stops generation within about a second. A moment of already-buffered video and audio may still play out, and no generation_complete follows. Emits generation_reset. To stop without losing the conditions, use stop instead.

Messages from model

With the base SDK, listen with reactor.on("message", ...). Every message arrives as JSON with a type and a data payload. The typed SDK gives you one hook per message, with the payload fields on the message itself:
All messages:
Each ..._accepted message fires once and is followed by a state_update carrying the same information. Render persistent UI from the snapshot and use the accepted messages as confirmations.

state_update payload

state_update is one snapshot of everything observable, so a client can render from it alone instead of accumulating the individual messages.
There is no single status string. Derive one from the booleans if you need it: generating and paused describe a take in flight, finished a completed one, and ready whether start would be accepted.
Example handler:

Complete example