---
title: "Render a scene to a WebM video with its sound (queued)."
method: POST
path: "/api/agents/run/video_render"
tags: ["Production engines"]
---

# Render a scene to a WebM video with its sound (queued).

`POST /api/agents/run/video_render`

## Request

- Base URL: `https://tomorrowlives.com`
- URL: `https://tomorrowlives.com/api/agents/run/video_render`
- Auth: HTTP bearer

Renders a scene to video.webm (VP9 and Opus), video.wav (its sound) and video.vtt (when it has subtitles); with preview (the default) also video.contact.png, twelve moments on one sheet, and video.preview.gif, 480 pixels wide. A scene can hold: drawn pictures with groups, flips and a multiply blend (a shadow, a vignette, a night grade); characters who talk (cast, timed lines with their own reading, ducked music, subtitles made from the lines, a mouth that moves on the words and eyes that blink); shots with people on paths, action beats (guard, strike, hit, fall, get-up) and gestures on cue (a wave, a point, a nod), animals and forms, and a camera that follows, orbits or cranes; music with a melody, a lead instrument and tempo changes; and sounds that move across the ears. Its files together are at most 50 MB, so a long, busy scene renders with preview false. At most 60 seconds, 1920 by 1080 either way up and 30 frames a second. The price is read off the engine's own cost report: units = design renders x megapixels / 45 + frames x megapixels / 200 + shot frames x megapixels / 1.6 + 3 a shot clip, rounded up; at most 600 a job, and video_cost says it first. It runs as a queued job: the answer is 202 with a job id at once, and GET /api/agents/jobs/<job> (or the MCP tool job) says when it is done and signs its files. A queued call is refused on the free plan with 402: its units buy only calls that answer at once, and queued jobs need a paid plan (a pass or the card plan). Each account may have 4 queued jobs waiting or running (1 running at a time), and may submit 20 videos and 10 minutes of video a day (UTC).

## Request body

- object
  - `scene` object, required: A scene document written inline: output (size, frame rate, length), tracks of clips, optional cast and lines, audio and subtitles. Start from video_examples and read video_schema for every key.
  - `preview` boolean: Also write the contact sheet and a small preview GIF (the default); false for a long, busy scene whose files would pass the size cap.

## Response `202`

Queued: the job id, its price and where to poll. Poll GET /api/agents/jobs/{job} until it is ok, refused or failed.

- QueuedJob: A queued job, as submitted. Its units already count against the allowance; a job the engine refuses, one the server never ran, or one whose files pass the 50 MB cap (error output_too_large) is not charged.
  - `job` string
  - `verb` string
  - `status` 'queued'
  - `units` integer
  - `created_at` string, date-time
  - `poll` object
    - `method` string
    - `path` string
    - `wait_max_s` integer
    - `hold` string
  - `retry_after_s` integer: When to ask first, in seconds; also the Retry-After header
  - `estimate` unknown

## Other responses

- `400`: The input is not valid
- `401`: No valid API key
- `402`: A pass or a payment is needed: a queued render on the free plan, a unit pack on the free plan (pass_required), a card plan's past-due renewal, or, on the free plan, an owner who has not confirmed their email yet (owner_unconfirmed; a pass needs no confirmation); or a payment did not go through (payment_failed, payment_token_unusable), and nothing was charged
- `403`: The account is suspended, the paying card is not from the United States (region_not_supported), or the address named as its owner said it is not theirs and costed runs are paused until a new owner is named (owner_removed)
- `413`: The input or the output is over its cap; a job stopped by the output cap is not charged
- `422`: The engine refused the input, a limit of the service's refused it (error: video_limit or pull_limit) or stopped the job, or the content policy refused the input (error: content_policy)
- `429`: A limit was hit; reset_at says when it lifts (also in Retry-After)
- `503`: The engines are busy or not installed
- `504`: The job ran past its time and was stopped

---

[API](https://skmtc.dev/tomorrowlives/apis/tomorrow-lives-engines.md) · [All operations](https://skmtc.dev/tomorrowlives/apis/tomorrow-lives-engines/llms.txt) · [OpenAPI document](https://skmtc.dev/tomorrowlives/apis/tomorrow-lives-engines/revisions/afc3d67322ac?raw)
