Stop a Seedance 2.5 batch on SumeInsufficientCreditsError

Submit a batch with createVideoGeneration and one idempotency key per item. On a 402, stop the loop, top up, and rerun the same script without paying twice.

5 min readSume
All posts

Give every item in the batch its own Idempotency-Key, check each submit for a 402, and break out of the loop when the SDK type says the workspace cannot fund the request. After a top-up, run the same script: items that were already accepted come back as the original jobs, and only the rest are new spend.

The generated SDK functions return a result object instead of throwing, so the typed error is one call away.

What does a 402 look like to the SDK?

The Sume client maps statuses to classes. For this batch, two matter, and the docs describe what to do about each.

SDK error classes used by a batch loop (@sume-com/sdk 0.2.0, read 2026-10-09)
ClassHTTP statusWhat the loop does
SumeInsufficientCreditsError402Stop; topping up is the only fix
SumeRateLimitError429The client already retried a keyed POST; slow down
SumeConflictError409Same key with a changed body; fix the key
SumeAuthenticationError401Stop; the key is wrong

How do I write the loop?

The index is part of the key, so the loop is replay-safe. toSumeApiError turns the status and body into the typed class.

import {
  createSumeClient, createVideoGeneration, toSumeApiError,
  SumeInsufficientCreditsError,
} from "@sume-com/sdk";

const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
const prompts = (process.env.PROMPTS ?? "").split("|").filter(Boolean);
const ids: string[] = [];

for (const [i, prompt] of prompts.entries()) {
  const { data, error, response } = await createVideoGeneration({
    client,
    headers: { "idempotency-key": `${process.env.BATCH}-${i}` },
    body: { model: "seedance-2.5", prompt,
            duration: 8, resolution: "720p" },
  });
  if (error || !data) {
    const err = toSumeApiError(response?.status, error, "submit failed");
    if (err instanceof SumeInsufficientCreditsError) {
      console.error(`out of credits after ${ids.length} jobs`);
      break;
    }
    throw err;
  }
  ids.push(data.id);
}
console.log(ids);

Why a break and not a retry?

The docs say a funding failure has one fix, and a retry cannot supply it. A 402 loop with backoff only burns time and, on the later items, writes noise into your logs. Break, save the printed ids, and let a person or a billing job top up.

How do I know the rerun reused the first jobs?

Print the job ids on both runs. For items that were accepted the first time, the ids match, because the same key with the same body returns the original job. Change a prompt between runs and that one item fails with a 409 instead, which is the signal that your key scheme is working.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume