TypeScript SDK: createVideoGeneration, then poll for 'cancelled'
The @sume-com/sdk video functions return {data, error, response} and never throw. An 18-line loop passes an Idempotency-Key and handles the British spelling.

Call createVideoGeneration with a body and an Idempotency-Key header, then poll getVideoGeneration and treat completed as success and failed or cancelled as the end. The generated functions in @sume-com/sdk resolve to { data, error, response } and do not throw on an HTTP error, so check error yourself. The /v1/videos route spells it cancelled, while /v1/jobs uses canceled.
Which function does what
Four generated functions cover the video route. They take a client from createSumeClient, which sends the key as x-api-key; never add an Authorization header as well.
| Function | Route | Use |
|---|---|---|
| createVideoGeneration | POST /v1/videos | Submit, 202 |
| getVideoGeneration | GET /v1/videos/{id} | Poll status |
| getVideoGenerationContent | GET /v1/videos/{id}/content | Download; 409 job_not_completed or job_failed |
| listVideoGenerationModels | GET /v1/videos/models | Read capabilities |
The loop
It type-checks against the SDK source. The header is passed through headers, which the SDK's retry rule looks for: it retries a POST on 408, 429 or 5xx only when an Idempotency-Key is present. The 15-second delay is a placeholder; a real worker should back off and cap the total wait.
import { createSumeClient, createVideoGeneration, getVideoGeneration } from "/tmp/sume-com-blog-trend-100/packages/sdk/src/index.ts";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
const created = await createVideoGeneration({
client,
body: { model: "wan-3.0", prompt: "a kite over a salt flat", duration: 10, resolution: "720p", aspect_ratio: "16:9" },
headers: { "Idempotency-Key": "kite-0001" },
});
if (created.error || !created.data) throw new Error(`submit failed: ${created.response?.status}`);
for (;;) {
await new Promise((r) => setTimeout(r, 15_000));
const polled = await getVideoGeneration({ client, path: { id: created.data.id } });
const status = polled.data?.status;
if (status === "completed") break;
if (status === "failed" || status === "cancelled") throw new Error(`ended as ${status}`);
}Other choices
The 0.2.0 npm package does not ship a waitForJob helper, as a linked post explains, so a polling loop like this one is the thing to write yourself.
The loop above is a sketch: it has no timeout and no AbortSignal. Add both before it runs unattended.
Sources
Related posts
More in Developers
- unittest the spreadsheet-row to Sume bulk item builder, no network
A pure function that turns a spreadsheet row into a Sume bulk item, with four unittest cases for trimming, price format, a spend cap in range and blank SKUs.
- unsupported_capability names sume/auto: fix a Sume ad clip request
A 400 unsupported_capability on sume/auto hides the resolved model but lists accepted values in supported. How to fix duration, resolution or audio.
- Format run cap headroom: usage.cap limit, counted and remaining
usage.cap on a run receipt splits the spend-cap check into limit, counted and remaining USD micros. Read it to see how close a run is to failing.
- /v1/videos size returns 400: send resolution and aspect_ratio
Every v1 Sume video model reports supported_sizes null, so a size field gets 400 unsupported_parameter. Send resolution and aspect_ratio; where to read values.
Written by Sume