SaaS onboarding videos: one avatar job per checklist step

Each avatar job runs 4 to 60 seconds. Make one short video per onboarding step with a per-step idempotency key and a webhook, instead of one long welcome video.

5 min readSume
All posts

For a SaaS onboarding checklist, make one avatar video per step instead of one long welcome video. Sume's avatar video accepts scripts that estimate to 4 to 60 seconds, so a 5-step checklist becomes five short jobs, each with its own idempotency key and a webhook, and each can be shown at the moment the user reaches that step.

Everything here is from the avatar video and webhooks docs. Sume does not know your product or your user data; you supply the script text and decide when each video is shown.

Why split onboarding into steps?

Scripts and multi-scene plans are accepted when Sume estimates the video at 4 to 60 seconds inclusive; longer scripts are told to shorten or split into multiple jobs. A single welcome video that tries to cover connecting data, inviting teammates and setting up billing will not fit in a minute.

Splitting also helps users. Someone stuck on step 3 wants the 40 second clip for step 3, not a 4 minute tour. A failed render redoes one step, not the whole thing.

How do I submit one job per step?

Use POST /v1/avatar-1.0/talking-video with a ready avatar_handle and exactly one of script or video_inputs. aspect_ratio defaults to 9:16 and quality to plus; for an in-app panel you probably want 16:9. Send mode: "webhook" with a public HTTPS webhook_url, and a distinct Idempotency-Key per step so a retry does not queue a second render.

The loop below submits three steps; the key combines the account and the step name:

ACCT=acme
for step in connect-data:"Connect your first data source in the Sources tab." invite-team:"Invite a teammate from Settings, then Members."; do
  name=${step%%:*}; script=${step#*:}
  curl -X POST https://api.sume.com/v1/avatar-1.0/talking-video \
    -H "Authorization: Bearer $SUME_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: onb-$ACCT-$name" \
    -d "{\"avatar_handle\":\"sume_clawra\",\"aspect_ratio\":\"16:9\",\"script\":\"$script\",\"mode\":\"webhook\",\"webhook_url\":\"https://example.com/sume-hook\"}"
done

How do I handle the callbacks?

Sume sends terminal events only: job.completed, job.failed and job.canceled. Use job_id as your idempotency key on receipt, return any 2xx after storing the event, and keep polling status_url as a fallback, because delivery is up to 10 attempts at a fixed spacing (30 seconds by default) with a 10 second timeout per attempt.

Verify the signature before trusting a body. The webhook docs give the scheme: HMAC SHA 256 over the timestamp, a dot and the raw body, sent in x-sume-webhook-signature as sume-v1=<hex>, with a timestamp tolerance of five minutes as a reasonable default. Refuse any delivery when your secret is empty.

Onboarding job design, read 2026-10-02
DecisionRule from the docsWhy it fits onboarding
Script length4 to 60 seconds estimatedOne step per video
Aspect ratio1:1, 3:4, 9:16, 4:3 or 16:9, default 9:16Pick 16:9 for desktop panels
Qualitystandard, plus (default) or maxstandard is the fastest path
DeliveryWebhook, with polling fallbackDo not block signup on a render

What can go wrong?

To preview a first frame before paying for a full render, see avatar video previews. For broader onboarding use cases, read customer onboarding video with an AI avatar, and for the length rule alone, avatar video longer than 60 seconds.

  • Long scripts: shorten or split, since over 60 seconds is rejected.
  • Inline captions on a script over 60 seconds are also rejected.
  • A webhook URL that is not public HTTPS is refused.
  • Sync mode waits only 30 seconds; render times are longer, so use async or webhook.
  • A step's video goes stale when the UI changes; regenerate it with a new idempotency key.

How should I store the results?

Save the job_id, the step name and the video_url from the finished result in your database, keyed by account and step. Your in-app checklist then reads from your own table, and a missing row tells you which step still needs a job.

Use the job's status_url as a fallback for any step whose webhook never arrived. Delivery is an optimization, not the only recovery path, as the webhook docs put it.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume