Avatar job tracking table: which Sume ids to store and why

Avatar work produces a handle, a job id, a preview id and a video id. A small SQL table that keeps them straight, plus the status fields to poll.

5 min readSume
All posts

Store five identifiers per avatar render and you can answer almost any support question later: the avatar_handle, the job id, the avatar_video_preview_id if you used a preview, the avatar-video resource id, and the Idempotency-Key you sent. Sume's avatar flow spreads state across several resources, and a table that keeps them on one row avoids a lot of API archaeology.

What each id is for

Identifiers in the Sume avatar flow (Sume docs, read 2026-10-07)
FieldWhere it comes fromWhy you keep it
avatar_handleYou choose it on avatar create; Sume stores it without a leading @The key you pass to every talking-video request
job idEvery submit returns a job; poll /v1/jobs/{id}/status and /resultRetry, events and failure triage
avatar_video_preview_idPreview create responseRegenerate stills or call generate-video from the preview
avatar-video idGET /v1/avatar-videos/{id}The finished video resource and its video_url
Idempotency-KeyYou generate itSafe retries without a second charge

A starter table

The SQL below is a plain schema, not a Sume object. Adjust types to your database.

CREATE TABLE avatar_renders (
  id               BIGSERIAL PRIMARY KEY,
  campaign         TEXT NOT NULL,
  avatar_handle    TEXT NOT NULL,
  quality          TEXT NOT NULL DEFAULT 'plus',
  idempotency_key  TEXT NOT NULL UNIQUE,
  preview_id       TEXT,
  preview_job_id   TEXT,
  render_job_id    TEXT,
  avatar_video_id  TEXT,
  script_text      TEXT NOT NULL,
  job_status       TEXT,
  resource_status  TEXT,
  video_url        TEXT,
  created_at       TIMESTAMPTZ NOT NULL DEFAULT now()
);

Two status columns, on purpose

The docs recommend resource_status for readiness of a preview or video and job_status when you poll the job. Keep both. A job can be in a terminal state while you still wait to read the resource, and a column for each makes that visible in a dashboard instead of a guess.

Store the quality tier you asked for. An empty body on generate-video keeps the tier chosen at preview create, and an explicit quality overrides only the final render. Preview stills are tier-independent, so changing the tier later does not need a new preview, but your cost report needs to know which tier was actually billed.

Store the script, not just its hash

Structural fields such as script, video_inputs, avatar_handle, scene and aspect_ratio need a new preview if you change them. When someone asks why a clip says something odd, the exact script text you submitted is the first thing to look at, and comparing it with the finished transcript is the fastest check. Keep the approved version in the row and the reviewer's name in a second table.

Idempotency also matters here. Using the same key with a different payload returns a conflict, so derive the key from the campaign and a version number, not from a timestamp.

When something goes wrong

Given a row, you can fetch events for the job id to see where a slow or failed render stopped, then read the avatar-video resource to see whether a usable file exists. You then decide whether to retry with a new key or to adopt the existing job.

Reading the table back

Three queries pay for the schema. Jobs without a video id after an hour show stuck or failed renders. Rows with the same campaign and different quality values show what you spent on re-rolls. Rows where resource_status is not ready but the job is complete show a read you forgot to do. Add an index on idempotency_key, which the UNIQUE constraint already provides.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume