waitForJob for a 30-second Seedance clip: TypeScript SDK example
With @sume-com/sdk, submit a seedance-2.5 job through generateVideoRouter and let waitForJob poll it for up to 20 minutes. Idempotency key, onStatus, errors.

Call generateVideoRouter with mode: "async" and an idempotency key, then pass the returned job id to waitForJob from @sume-com/sdk. The helper polls for you, with a 20-minute default timeout, a 2-second floor on the interval, and a server-suggested delay when next_poll_after_seconds asks for more.
Generated operations resolve with { data, error, response } and do not throw on an API error, so check error before you read data.
What the helper does
waitForJob resolves with the job record from /v1/jobs/:id, for any terminal status. A failed job is a result you read, not an exception. It throws SumeJobTimeoutError if the timeout wins, and SumeJobRequestError if a status read fails for good. Both carry the job id.
Transient 429 and 5xx reads do not end the wait. The job still runs and bills, so the helper backs off and polls again.
| Option | Default | Note |
|---|---|---|
| timeout | 20 minutes | Throws SumeJobTimeoutError, job keeps running |
| pollInterval | 2 seconds | A floor, server hint wins when longer |
| signal | none | Aborts the wait |
| onStatus | none | Called on every status read |
Run it
Install with npm install @sume-com/sdk. The package needs fetch and WebCrypto, so Node 18 or later works. Save the file as clip.mjs.
import { createSumeClient, generateVideoRouter, waitForJob } from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY });
const { data: sub, error } = await generateVideoRouter({
client,
headers: { "idempotency-key": "mug-orbit-ts-001" },
body: {
model: "seedance-2.5",
prompt: "Slow orbit around a ceramic mug on a desk",
duration: 30,
resolution: "720p",
mode: "async",
},
});
if (error) throw new Error(JSON.stringify(error));
const job = await waitForJob(sub.data.request_id, {
client,
onStatus: (status) => console.log(status),
});
console.log(job.status, job.result?.artifacts?.[0]?.url);Two cautions
The client sends x-api-key only. If a wrapper adds an Authorization header too, the API rejects the request with 401. Keep the key on the server: there is no browser-safe variant.
After a timeout, store the job id. Read it later with getApiJob, or cancel it with cancelApiJob before generation starts.
Sources
Related posts
More in Developers
- waitForJob polls every 2 s: 600 reads in a 20-minute Sume video job
The SDK's waitForJob floor is a 2-second poll and a 20-minute timeout: at most 600 reads per job. The read budget by plan and why next_poll_after_seconds wins.
- Wan 3.0 30-second clip via API: request, poll and the $3.75 price
Ask for model wan-3.0 with duration 30 on Sume's POST /v1/videos. At 720p the clip prices at $3.75 on Sume; here is the request and a poll loop.
- Wan 3.0 API in Node: vertical image-to-video from a first frame
Call Wan 3.0 on Sume from Node with fetch: pin a first frame, ask for 9:16 at 720p, poll the job and save the MP4. Includes limits and the 8-second price.
- Wan 3.0 API request cheat sheet: three modes, 2 to 30 seconds
Wan 3.0 on Sume: the request body for text, first/last frame and reference modes, the 480p/720p/1080p rates and the 2 to 30 second window, on one page.
Written by Sume