Zeli AvatarDeveloper docs

API reference / Avatar videos

Avatar videos

We do not render a script to a video file

There is no route that takes a script, speaks it and hands back a downloadable MP4. Nothing on this service writes an MP4 of spoken audio at all. If that is what you are looking for, stop here: the honest answer is that it does not exist, and the rest of this page is a different thing that shares the word "video".

What we do generate is emotion tone clips: short, silent, looping renders of one avatar in one delivery tone, built once and then lip synced at speaking time. Generating one is a real asynchronous job, with the same submit, poll and fetch shape a rendering API uses, so it is documented that way.

MethodPathPurposeAuth
GET/api/avatar/clipsEvery tone this avatar server has a view on, for one avatarany
POST/api/avatar/clips/retryGenerate one tone. 202any
GET/api/avatar/clipOne rendered clip, as MP4 bytesany

Two routes that look adjacent and are not

Worth naming before you map them by their names:

  • GET /api/videos lists avatar source uploads, not rendered jobs. It is documented under Avatars.
  • POST /offer lip syncs a pre uploaded audio file into a live WebRTC stream. There is no script in it, no text to speech in it, and it leaves no artefact behind. It is documented under Engine.

List clip states

GET/api/avatar/clips
avatarstringRequired

An avatar id, or any of its variant ids. Query parameter.

curl "https://zeli-avatar.zelibot.xyz/api/avatar/clips?avatar=acme-host" \
  -H "X-Api-Key: zsk_live_..."
{
  "avatar": "acme-host",
  "clips": [
    {
      "tone": "confident",
      "state": "generated",
      "variant_id": "acme-host__confident",
      "duration_s": 4.2,
      "updated_at": 1769903600,
      "detail": ""
    }
  ]
}
stateMeaning
generatedThe clip exists and is streamable
generatingA build is in flight. It takes minutes
failedThe build ran and did not produce a clip. detail says what happened
not_requestedThis tone was never asked for
Sparse on purpose

A tone this avatar server has never been asked for is absent from the array rather than listed as not_requested. That keeps the tone vocabulary in one place and stops the avatar server asserting opinions about tones it has never heard of. Treat a missing tone as not requested, not as an error.

A 404 means no such avatar on this avatar server, of yours. Not found and not yours are the same answer.

Generate one tone

POST/api/avatar/clips/retry
avatarstringRequired

The avatar id, or any of its variant ids.

tonestringRequired

A tone this deployment builds. Anything else is a 400.

curl -X POST "https://zeli-avatar.zelibot.xyz/api/avatar/clips/retry" \
  -H "X-Api-Key: zsk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"avatar": "acme-host", "tone": "confident"}'

Response 202, not 200, because the answer does not exist yet. A build is minutes long and the outcome arrives through GET /api/avatar/clips:

{
  "avatar": "acme-host",
  "tone": "confident",
  "variant_id": "acme-host__confident",
  "state": "generating"
}

Refusals, in the order they are checked

Every refusal happens before a generator is constructed, because each call is about a minute of metered generation.

StatuscodeWhen
404unknown_avatarNot an avatar on this avatar server, or not yours
400unknown_toneThis deployment builds no tone by that name
501avatar_clips_unavailableThis avatar server does not generate emotion clips
403consent_requiredNo attestation on record, or the photograph it attested to is gone
409clip_already_generatingThat exact variant is already building. Wait, do not loop
503clip_generator_unavailableThe generator is not reachable right now
Owning the avatar is not the same as having attested

Animating a likeness again is a new animation, so it goes through the same consent gate the original upload did: the attestation from the ledger, the owner from the live credential, and the photograph re hashed against what was agreed to. A video upload, and an upload whose consent never reached the avatar server, both leave a record with an owner and no attestation, and neither may generate a clip.

Fetch a clip

GET/api/avatar/clip
avatarstringRequired

The avatar id.

tonestringOptional

Which tone. Defaults to the deployment's default tone.

Returns MP4 bytes, not JSON, and is authenticated like every other avatar server route. That is why a browser fetches it into a blob rather than pointing a video element at it: the alternative is a live credential in a query string, which lands in access logs, referrer headers and history. The response is marked private caching, because the edge in front of an avatar server is shared.

Errors use the structured envelope: { "error": { "code": "...", "message": "..." } }.

The build journal

Clip builds also report through builds on GET /api/avatars, keyed by avatar. That key is on a list route rather than on the create response for a structural reason: the upload answers in milliseconds and the build takes minutes, so the create response is written before the outcome exists. A client polling the avatar list gets the answer on a request it was already making.

Not served in this group

  • Script to video. Named again because it is the thing most people arrive looking for. No route accepts a script, and no route returns a rendered file of spoken audio.
  • A job id, a job list and job filters. A clip is addressed by (avatar, tone) rather than by a job identifier, so there is no GET /avatar-videos to page through and no status, createdAfter or createdBefore filtering.
  • Cancel. The in flight claim is released only by the build task itself. No request can release it.
  • An expiring download URL for a clip. The bytes come back from the avatar server directly. The presigned URL mechanism does exist and is used for avatar media on the portal plane; it is not wired to clips.
  • An idempotency key header. It appears nowhere on this surface. Use the 409 instead: a second call for a variant already building is refused rather than charged twice.
Zeli Avatar · real-time avatars over WebRTC · self-hostable · AU data residency · source