sync-3 lip sync takes 10-15 min: async job and webhook pattern
Sync lists sync-3 at about 10-15 minutes for a 30 s video. Do not hold a request open: submit async, take a terminal webhook, and keep polling as a backup.

Sync's generation-times page puts sync-3 at about 10-15 minutes for a 30-second video and about 45-55 minutes for two minutes. Any job that long should be submitted asynchronously: on Sume the default mode is async, sync and subscribe waits stop at 30 seconds, and a webhook fires on terminal states only.
Timings are Sync's estimates; Sume behavior is from Jobs and results and Generation admission, read 2026-10-01.
How long does lip sync take by model?
| Model | 30 s video | 2 min video |
|---|---|---|
| lipsync-2 | about 1-3 min | about 4-8 min |
| lipsync-2-pro | about 2-5 min | about 6-12 min |
| sync-3 | about 10-15 min | about 45-55 min |
| react-1 | about 1-2 min | n/a (max 15 s input) |
How does Sync say to track a generation?
Poll the generation endpoint, recommended every 10 seconds, until the status is COMPLETED, FAILED or REJECTED, or configure a webhook, which the page calls more efficient for production. It also warns against resubmitting a stuck job because that adds queue entries without canceling the original.
What is the matching pattern on Sume?
Sume's default async mode returns 202 with the job envelope and polling URLs. sync and subscribe wait at most 30 seconds; if the job is not terminal, poll and do not resubmit. The webhook schema says delivery is terminal-only (job.completed, job.failed, job.canceled) with no progress callbacks, so keep status_url polling as a backup. The docs say to prefer async submit with an idempotency key in production. See also sync vs async video generation.
const API = "https://api.sume.com";
const headers = {
Authorization: "Bearer " + process.env.SUME_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": "avatar-batch-001-item-001",
};
const res = await fetch(API + "/v1/avatar-1.0/generate", {
method: "POST",
headers,
body: JSON.stringify({
avatar_handle: "studio_presenter",
input: { type: "prompt", prompt: "Friendly studio presenter" },
mode: "async",
}),
});
const job = await res.json();
const statusUrl = new URL(job.status_url, API);
let state = { terminal: false };
while (!state.terminal) {
await new Promise((r) => setTimeout(r, 10000));
state = await (await fetch(statusUrl, { headers })).json();
}
console.log(state);What should I avoid?
Do not treat a client timeout as a failure and resubmit the paid request; read the same job id instead. Poll with backoff across many jobs rather than in a tight loop.
Sources
Related posts
More in Developers
- Sync Labs batch API (20 to 500) vs Sume bulk runs (1 to 100)
Sync Labs batch takes 20 to 500 lip sync generations in one JSONL file on Scale and Enterprise. Sume bulk runs queue 1 to 100 Format runs with a 1 to 16 window.
- Sync Labs API rate limit: 100 per minute, and Sume headers
Sync Labs allows 100 POST /v2/generate and 600 GETs a minute. Sume has a per-plan requests-per-minute budget; read ratelimit headers and retry-after.
- Sync lip sync output: H.264 crf 17, HDR to SDR, alpha removed
Sync re-encodes lip sync output to H.264 at crf 17, turns HDR into SDR and drops alpha. Here is that next to what Sume returns for avatar video.
- Sync sync_mode bounce, cut_off, silence, remap vs Sume lengths
Sync offers bounce, cut_off, silence and remap when audio and video lengths differ. Sume has no such option: trim or split audio to the accepted window.
Written by Sume