Seedance 2.5 estimate vs usage.cost: reconcile a job in Node

Compute the Seedance 2.5 price from width, height and seconds, submit one job to Sume, and compare it with usage.cost on the poll. A runnable Node 18 script.

5 min readSume
All posts

To check that your Seedance 2.5 price math matches what Sume charges, compute the estimate before you submit, then read usage.cost from the poll response and compare. For an 8-second 16:9 clip at 720p the estimate is $4.63: 172,800 video tokens x $0.0214 per 1,000 x 1.25, rounded up to the cent. The script below does the whole check in Node 18 or newer.

usage.cost is the Sume billable amount on the poll response, per the video docs (read 2026-10-07). Run it once per resolution you plan to use at volume, and keep the output with your billing notes.

The script

Save it as reconcile.mjs (top-level await needs an ES module) and run SUME_API_KEY=... node reconcile.mjs. It submits one real job, so it spends about the estimate.

const key = process.env.SUME_API_KEY;
if (!key) throw new Error("Set SUME_API_KEY");
const headers = { Authorization: `Bearer ${key}`, "Content-Type": "application/json" };

const seconds = 8;
const tokens = Math.ceil((1280 * 720 * seconds * 24) / 1024);
const estimate = Math.ceil((tokens / 1000) * 0.0214 * 1.25 * 100) / 100;

const res = await fetch("https://api.sume.com/v1/videos", {
  method: "POST",
  headers,
  body: JSON.stringify({
    model: "seedance-2.5",
    prompt: "A paper boat drifts down a rain gutter, camera follows at water level",
    duration: seconds, resolution: "720p", aspect_ratio: "16:9",
  }),
});
if (!res.ok) throw new Error(await res.text());
const job = await res.json();

const deadline = Date.now() + 20 * 60 * 1000;
while (Date.now() < deadline) {
  await new Promise((r) => setTimeout(r, 15000));
  const s = await (await fetch(job.polling_url, { headers })).json();
  if (s.status === "completed") {
    console.log({ estimate, billed: s.usage.cost });
    process.exit(0);
  }
  if (s.status === "failed" || s.status === "canceled" || s.status === "cancelled") throw new Error(s.error ?? s.status);
}
throw new Error("timed out waiting for the job");

What to change, and when the numbers differ

The rate in the script (0.0214 per 1,000 tokens) is the provider list rate for seedance-2.5 at 480p and 720p; 1080p uses 0.0234. If you change the resolution, change the pixel size and the rate together: 1920x1080 and 0.0234 for 1080p. The 24 is the pricing frame rate that Sume's estimator uses.

If billed ever differs from estimate, trust billed and compare the model's pricing_skus in GET /v1/videos/models. A reference video in the request changes the math (0.6x over the output plus an assumed 15 seconds), so this script does not apply to those jobs.

Polling and failure

The poll loop waits 15 seconds between calls and stops after 20 minutes. A 30-second clip is not slow enough to need more; if a job passes the deadline, check its status before you submit another, so you do not pay twice.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume