---
title: "Prepare a scene (preview)"
method: POST
path: "/v1/scenes"
tags: ["Scenes"]
---

# Prepare a scene (preview)

`POST /v1/scenes`

## Request

- Base URL: `https://realtimeavatar.ai/api`
- URL: `https://realtimeavatar.ai/api/v1/scenes`
- Auth: HTTP bearer

Prepare a scene: a supplied clip registered once into an artifact a session can play in place of the avatar's source video (mint with scene.video_cache_id). The id is derived from the clip's content (md5 and size), not its URL, so the same bytes give the same id; a repeat request whose md5 and bytes are already built answers ready without a download. The answered id is bound to this workspace: only a scene the workspace prepared can be read back or minted, and a mint also requires it to be ready (409 scene_not_ready otherwise). 202 while building; poll GET /v1/scenes/{sceneId}. 200 once ready or failed. A failed state carries error: source_unreachable (the bytes never arrived; retry with a bounded backoff), source_unusable (supply a different clip), source_mismatch (the bytes differ from the declared md5 or bytes) or build_failed. Its scene_id is "unresolved" when the download failed before any byte was hashed and the request declared no md5 and bytes.

Requires an API key with the `realtime:write` scope.

## Request body

- CreateSceneRequest
  - `source` object, required: The first clip. Played forward over its full length.
    - `url` string, uri, required: An https URL the builder can fetch. Hosts are allowlisted by the builder.
    - `md5` string: MD5 of the clip bytes. With bytes, lets an already-built scene answer ready without a download.
    - `bytes` integer: Clip size in bytes (at most 64 MiB).
  - `continuation` object: Optional return clip appended after the first. When its last frame matches the first clip's first frame, the loop closes seamlessly.
    - `url` string, uri, required: An https URL the builder can fetch. Hosts are allowlisted by the builder.
    - `md5` string: MD5 of the clip bytes. With bytes, lets an already-built scene answer ready without a download.
    - `bytes` integer: Clip size in bytes (at most 64 MiB).
  - `profile` 'scene-v0', required

## Response `200`

Ready or failed

- union
  - object
    - `status` 'building', required
    - `scene_id` string, required: The prepared scene's artifact id, as returned by POST /v1/scenes when status is ready.
    - `timings` object
      - `download_ms` number
      - `decode_ms` number
      - `geometry_ms` number
      - `write_ms` number
      - `total_ms` number
  - object
    - `status` 'ready', required
    - `scene_id` string, required: The prepared scene's artifact id, as returned by POST /v1/scenes when status is ready.
    - `video_cache_id` string: The prepared scene's artifact id, as returned by POST /v1/scenes when status is ready.
    - `fps` number
    - `width` integer
    - `height` integer
    - `first_frames` integer
    - `total_frames` integer
    - `duration_s` number
    - `timings` object
      - `download_ms` number
      - `decode_ms` number
      - `geometry_ms` number
      - `write_ms` number
      - `total_ms` number
  - object
    - `status` 'failed', required
    - `scene_id` union, required: The scene id, or "unresolved" when the download failed before any byte was hashed and the request carried no md5 and bytes.
      - string: The prepared scene's artifact id, as returned by POST /v1/scenes when status is ready.
      - 'unresolved'
    - `error` 'source_unreachable' | 'source_unusable' | 'source_mismatch' | 'build_failed'
    - `timings` object
      - `download_ms` number
      - `decode_ms` number
      - `geometry_ms` number
      - `write_ms` number
      - `total_ms` number

## Other responses

- `202`: Building
- `401`: Missing, malformed, revoked, or expired key.
- `403`: The key lacks the scope for this operation, the tenant is not active, or scene sessions are not enabled for the workspace — code "scene_sessions_not_enabled", a per-workspace preview gate. Contact support to opt in.
- `default`: Error. Route-dependent: 400 (a field this route cannot honour — see `portraitUrl` on `UpdateAvatarRequest`), 402 (insufficient credits or spend limit), 404 (no such avatar, voice, or key for this tenant — the message often reads "does not belong to this tenant", which is a missing id and not a permission failure), 408 (the request was cancelled), 409 (the resource is not in a state that accepts this write — a stale `expectedRevision`, a render already in flight, or a mint that asked for a clip library still building), 411 (`POST /v1/assets/remote` only — the origin serving `remoteUrl` sent no `content-length`, so the platform will not stream it), 422 (strict schema rejection, or a motion description the safety screen refused), 429 (rate limited), 502 (upstream render failed), 503 (a dependency this route needs is unavailable — retryable, and nothing was written), 504 (the upstream request budget expired), 500 (unhandled). Switch on `code` where present, else `status`.

---

[API](https://skmtc.dev/realtimeavatar/apis/realtime-avatar-api.md) · [All operations](https://skmtc.dev/realtimeavatar/apis/realtime-avatar-api/llms.txt) · [OpenAPI document](https://skmtc.dev/realtimeavatar/apis/realtime-avatar-api/revisions/e9e3e998e673?raw)
