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:
- queued — created with the merged script, waiting for your render runtime to pick it up.
- rendering — your runtime has started the render.
- completed — terminal. Carries
output_urlplus the content credential minted at completion. - failed — terminal. Carries a human-readable
error.
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 with400 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 likefirst_name(not{{first_name}}).
{{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 reportscompleted 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.
Provenance handoff
Completing a job mints a content credential — a tamper-evident, signed provenance manifest — and persists it on the job ascontent_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: oncecompleted 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.
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 itsoutput_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.
Related
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.