Node quickstart: your first Wan 3.0 video on Sume and what 30 s costs
Node 18 fetch script: POST /v1/videos with wan-3.0, poll, print the URL. The list-price arithmetic for 30 s at 480p, 720p and 1080p, times the 1.25 margin.

With Node 18 or newer you need no packages: fetch POST /v1/videos with model wan-3.0, read the id from the 202, poll GET /v1/videos/{id} until completed, and print unsigned_urls. A 30-second 1080p Wan 3.0 clip has a list price of $6.00, and Sume bills list times 1.25, so $7.50, which you can compute before you press enter.
What you need
Create an API key in the dashboard and export it as SUME_API_KEY. Keep it on the server. Sume's docs are blunt that a key spends your credits and has no browser-safe variant, so run this on your machine or a backend, never in client JavaScript.
Wan 3.0 in the catalog takes 2 to 30 seconds at 480p, 720p and 1080p, with audio, for text, image with end frame, and reference input. Its list price is resolution-tiered per second.
Why start at 480p? A first test should prove the plumbing, not the pixels. At 480p a 30-second Wan 3.0 clip has a list price of $1.50, which is $1.88 billed after the 1.25 margin and the round-up, so you can run the script a few times while you tune the prompt. Raise the resolution to 1080p only once the prompt and the polling are right.
Price before you run
The Video Router docs list Wan 3.0 at $0.05, $0.10 and $0.20 per second for 480p, 720p and 1080p, from fal on 2026-08-24, and say Sume bills the list price times 1.25, rounded up to the cent. The arithmetic for a 30-second clip is below, and the workspace balance is reserved at submit.
| Resolution | List per second | 30 s at list | Times 1.25 billed |
|---|---|---|---|
| 480p | $0.05 | $1.50 | $1.875, rounded up to $1.88 |
| 720p | $0.10 | $3.00 | $3.75 |
| 1080p | $0.20 | $6.00 | $7.50 |
The script
Save as clip.mjs and run node clip.mjs. It uses a stable Idempotency-Key, so running it twice by accident does not make two jobs. Change resolution to 480p for a cheap first test.
const BASE = "https://api.sume.com";
const headers = {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
};
const submit = await fetch(`${BASE}/v1/videos`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": "quickstart-wan-30s-001" },
body: JSON.stringify({
model: "wan-3.0",
prompt: "A paper boat drifting down a rain gutter, macro, soft light",
duration: 30,
resolution: "480p",
aspect_ratio: "16:9",
}),
});
const job = await submit.json();
if (submit.status !== 202) throw new Error(JSON.stringify(job));
for (let wait = 2000; ; wait = Math.min(wait * 1.5, 30000)) {
await new Promise((r) => setTimeout(r, wait));
const poll = await (await fetch(job.polling_url, { headers })).json();
console.log(poll.status);
if (["completed", "failed", "cancelled"].includes(poll.status)) {
console.log(poll.unsigned_urls ?? poll.error);
break;
}
}
What to expect
The first line you see is the status after two seconds, likely pending or in_progress. Statuses are pending, in_progress, completed, failed and cancelled on this route. A completed job gives you a URL on api.sume.com that needs your key and redirects to the file, so download it with the same Authorization header and without forwarding it to the redirect target.
If the submit returns 402, your balance is below the reserve. If it returns 400 unsupported_capability, you asked for a value the model does not list. Both come back before any generation starts.
One detail in the script is easy to miss: it polls job.polling_url, the URL Sume returned, not a URL you built. That keeps you correct if the host or path ever changes, and it is the same pattern as the OpenRouter video guide, where the submit answer hands you the polling URL.
Next steps
- Swap the model for seedance-2.5 to compare. Its duration range is 4 to 30 seconds.
- Move from polling to callback_url once the first run works.
- Use sume/auto if you do not want to pin a family, but it resolves to the Omni 1.1 envelope of 3 to 10 seconds.
- Read the live catalog with GET /v1/videos/models, since prices and limits move.
Sources
Related posts
More in Developers
- Node stream.pipeline to save a Sume MP4 and catch truncation
Stream a finished Sume video to disk with stream.pipeline, then compare bytes written with content-length so a cut-off MP4 never reaches your users.
- Gemini Omni edit input is capped at 10 seconds: trim first on Sume
Google says Omni edit inputs must be 10 seconds or less. Cut the clip with Sume's video-trim at $0.02 a job, then send the short clip to the edit request.
- Gemini Omni audio is always on: generate_audio false returns 400
Sume's Omni row rejects generate_audio false with a 400 because audio is native and always on. To ship a silent clip, drop the track with video-trim after.
- Omni edit: one change per turn or one combined prompt, and the cost
Three single-change Omni edits on a 10 s clip are $3.75 at 720p; one combined prompt is $1.25. Per-turn is 3x the price, so pick by how a failed edit costs you.
Written by Sume