Skip to main content

Avatar video render lifecycle

An avatar persona can join a live room, but it can also render a personalized video clip from a text script — the asynchronous counterpart to the live join. That render is modeled as a pollable job: POST /api/v1/video/avatar-video-renders script it, your render runtime performs the render off-platform, and PATCH transitions report the result back. This page is the model behind that loop. Request shapes live in the video API reference; the avatar bot dispatch queue page covers the live-join path.

The render-job state machine

A render job (vavr_… id) has four statuses:
  1. queued — created with the merged script, waiting for your render runtime to pick it up.
  2. rendering — your runtime has started the render.
  3. completed — terminal. Carries output_url plus the content credential minted at completion.
  4. failed — terminal. Carries a human-readable error.
Allowed transitions are queued → rendering, queued/rendering → completed, and queued/rendering → failed. Both terminal states reject further transitions with a 409 VIDEO_AVATAR_RENDER_INVALID_TRANSITION, so each job is append-only: a terminal verdict can never be overwritten while the job still exists (see deletion below). A completed report without an output_url, or without its provenance credential, is rejected outright.

Authoring inputs

You create a job with four authoring inputs:
  • avatar_agent_id — the persona to render from (vaa_… id, created in Video → Avatar agents). The persona must be enabled; a disabled persona rejects the job with 400 VIDEO_AVATAR_RENDER_INVALID.
  • script_template — the text the avatar speaks (up to 5,000 characters), with {{merge_field}} tokens.
  • locale — optional TTS language override (up to 35 characters); without it, the persona’s own locale applies.
  • merge_fields — token substitutions, where each key is a bare token name like first_name (not {{first_name}}).
Unresolved tokens are rejected up front. A rendered clip is a single deterministic render — unlike a mass campaign send, there is no per-recipient fallback that could fill a blank value later, so every {{token}} you write must have a supplied value at script time. A missing value returns 400 naming the missing tokens, before any render work is queued.

Completion contract

When your render runtime has the clip, it reports completed over PATCH /api/v1/video/avatar-video-renders/:id. The report must bind the clip in one of two ways:
  • video_base64 — the raw clip bytes. Orbit decodes them and computes the SHA-256 digest server-side, so an empty or mislabeled payload is caught before the credential is minted.
  • video_sha256 + video_bytes — a pre-computed digest and byte count, for when the clip is too large to attach.
Orbit never calls the provider render API (Tavus, HeyGen, D-ID, …) directly and stores no provider credentials — your own render runtime, holding its own credentials, performs the render and this PATCH is its callback. That separation is what lets a completion report arrive without embeddable clip bytes and still prove which clip it refers to.

Provenance handoff

Completing a job mints a content credential — a tamper-evident, signed provenance manifest — and persists it on the job as content_credential, next to the output_url. The manifest binds the clip bytes (video_sha256), the exact rendered script (script_sha256), the persona, the tenant, and the render provider, so the credential travels with the clip when you attach the URL to a campaign send or a 1:1 message. A completed transition that would skip that mint is rejected — every completed clip must carry the manifest, never just a subset. Verification (POST /api/v1/video/avatar-video-renders/verify) is stateless and read-scoped: pass the token to check its signature, and optionally pass video_base64 or video_sha256 to confirm it is still bound to the clip in hand (video_mismatch otherwise). The full marking model is in synthetic-media provenance.

Limits

All limits are enforced at script or completion time, so a failed request never consumes render capacity:
  • Script template: 5,000 characters.
  • Merge fields: 20 keys; key ≤ 64 characters; value ≤ 500 characters each.
  • Locale: 35 characters.
  • Output URL and error message: 2,048 / 500 characters.
  • Per-tenant job history: 200 jobs — the library is bounded, so create #201 rejects until you delete old jobs.

Idempotency and PATCH callbacks

PATCH transitions are safe to retry within the same terminal verdict. The state machine collapses a duplicate callback onto the same outcome: once completed or failed is recorded, any further PATCH is a 409, and the first answer stands. A rendering report arriving before the completion report is accepted but is not required — queued → completed is a legal direct transition. This is what makes the completion callback retry-safe without an idempotency key: the terminal-state gate is the dedupe.

Relationship to the dispatch queue

These two concepts split the surface cleanly:
  • Avatar bot dispatch queue — the live join: dispatching a persona into a real-time room with roster verification.
  • This page — the async render: script → clip that outlives any room.
Both resolve personas from the same registry, and both follow the non-secret-reference design: Orbit persists the request and a plain handle, your integration runtime holds provider credentials and performs the actual work.

Tenant audit and deletion

Every transition — create, status update, delete — is written to the tenant audit ledger with the persona id, status, and whether an output and credential are present. DELETE /api/v1/video/avatar-video-renders/:id removes a job from the rendering history free-form (terminal or not); the audit entry persists past the job itself. Deletion is how you keep the bounded 200-job history from rejecting new renders, and it lets your compliance retention policy clear rendered-script text without touching live traffic.

Scope note

The render surface produces a video asset only. Attaching its output_url to a campaign or message send always exits through the Devotel softswitch-backed send path; no outbound (MT) voice or SMS leg is ever originated here.

Synthetic-media provenance

The full content-credential model the completion handoff mints.

Avatar bot dispatch queue

The live-join counterpart: persona-to-room dispatches and roster verification.

AI video avatar agents — guide

Persona registry, join plans, and render jobs end to end.

Audit ledger model

Where every transition’s audit entry lands and how to query it.