What happens at zero credits mid-batch: 402 on Sume

When a Sume balance cannot cover a generation the API returns 402 insufficient_credits. Failed jobs are refunded before capture. Cap a batch locally.

5 min readSume
All posts

When the balance cannot cover a generation, Sume returns HTTP 402 with the error code insufficient_credits, and the job is not accepted. A job that fails or is canceled before generation starts is refunded before capture. So a batch that runs out of credit stops at the first rejected submit, not halfway through a clip.

The 402 case

The errors page lists 402 insufficient_credits as: the balance is not sufficient for the requested generation. The catalog's reservation policy explains the mechanics: at submit time the estimated amount is stored in USD micros, rounded up to cents for the balance check, captured on completion, and refunded when a job fails or is canceled before generation.

The practical effect is that the balance check is against the estimate of the job you are submitting plus the holds of jobs already in flight. A 100-clip batch can therefore fail at clip 80 even if the balance looked large at the start.

Credit behavior on Sume, from the catalog and the errors page, as of 2026-10-09
SituationWhat Sume doesWhat you do
Balance below the job's estimate402 insufficient_creditsAdd funds or reduce the request cost
Too many requests429 rate_limited, with retry-afterBack off, reuse the Idempotency-Key
Workspace queue full429 queue_fullWait for a job to finish or cancel one
Job fails or is canceled before generationRefunded before captureRetry with the same key if retryable
Job category quotaAdd funds, or decrease the request costCheck the job error metadata

Cap it yourself

The cheapest guard is a local counter. For 8-second Seedance 2.5 clips at 720p, each is 8 x $0.5778 = $4.6224. With a $100 cap, 21 clips cost $97.07 and a 22nd would reach $101.69, so the loop stops after 21.

The script below does that. It refuses to run without a key, keeps a running estimate, stops at the cap, and also stops on any HTTP error, including 402. An Idempotency-Key per clip is there so a retry of the same submit does not create a duplicate.

After the stop

Check the jobs you did submit with the job status endpoint, then top up and resume from the next index. Keep a record of which indexes were accepted so you resume from the next one; deterministic keys (batch-0 to batch-99) make retries of the same index safe to attempt.

Queue behavior is separate: a full queue returns 429 queue_full, not 402. Full concurrency alone is not an error while queue capacity remains.

A second scenario

Size the cap for a different clip. For 8-second 720p clips at $4.6224 each, a $250 cap allows $250 / $4.6224 = 54.08, so 54 clips costing $249.6096. If you also want a 10 percent reserve for retakes, set the loop cap to $225 and it stops at 48 clips ($221.88). Change PRICE and CAP in the script to match your plan.

A local cap with a stop on 402

A minimal loop using only the standard library and a $100 cap:

import asyncio, os, urllib.request, urllib.error, json

KEY = os.environ.get("SUME_API_KEY", "")
PRICE = 0.5778 * 8  # seedance-2.5, 720p, 8 s
CAP = 100.0

def submit(i):
    body = json.dumps({"model": "seedance-2.5", "prompt": f"clip {i}",
        "resolution": "720p", "duration": 8, "mode": "async"}).encode()
    req = urllib.request.Request("https://api.sume.com/v1/video-router/generate", body,
        {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json",
         "Idempotency-Key": f"batch-{i}"})
    return urllib.request.urlopen(req).status

async def main():
    if not KEY:
        raise SystemExit("SUME_API_KEY is empty")
    spent = 0.0
    for i in range(100):
        if spent + PRICE > CAP:
            print("local cap reached at", i); break
        try:
            await asyncio.to_thread(submit, i)
            spent += PRICE
        except urllib.error.HTTPError as e:
            print("stopped:", e.code); break
    print("held about", round(spent, 4))

asyncio.run(main())

Reproduce the numbers

Open https://api.sume.com/v1/catalog, which needs no key, and find the entry for the product. Each model_pricing row carries price, unit, pricing_basis and the estimated, minimum and maximum cents. Multiply the unit price by your quantity and round only at the end. The catalog also has applied_* fields that include an agent fee of 550 basis points; the figures in this post use the base prices.

Sources

Related posts

More in Pricing

All Pricing posts

Written by Sume