Price guard: refuse a 30-second Seedance 2.5 render over your cap

Compute the Sume price of a clip from model, resolution and seconds before you POST, and refuse over a cap. Python code, the rates, and the 1080p cent rounding.

5 min readSume
All posts

You can refuse an expensive render before you send it by computing the clip's Sume price from the model, the resolution, and the seconds, and comparing it with a cap you set. A 30-second Seedance 2.5 clip is $8.07 at 480p, $17.34 at 720p, and $42.65 at 1080p, so a guard that rejects anything over, say, $20 stops the 1080p mistake automatically.

The guard is yours, not Sume's. It is a cheap local check that sits in front of the paid call, and Sume's own reservation at submit remains the authority.

The rates to encode

Sume bills provider list times 1.25. Wan 3.0 lists at $0.05, $0.10 and $0.20 per second, which makes $0.0625, $0.125 and $0.25 per second on Sume. Seedance 2.5 is billed by video tokens in the pricing tables, and the per-second rates that reproduce the Sume cents at 4, 10, 15 and 30 seconds are about $0.269 at 480p, $0.578 at 720p, and $1.42155 at 1080p, rounded up to the cent.

Sume price of a clip by length, rounded up to the cent, Sume pricing tables read 2026-10-05
ModelResolution10 s30 s
Seedance 2.5480p$2.69$8.07
Seedance 2.5720p$5.78$17.34
Seedance 2.51080p$14.22$42.65
Wan 3.0480p$0.625$1.875
Wan 3.0720p$1.25$3.75
Wan 3.01080p$2.50$7.50

The guard

This standard-library function raises before any network call. The Wan rows are exact; the Seedance rows are tuned to match the published cents, so treat the table as a cache that you re-check against the pricing tables when rates change.

import math

RATE = {  # USD per second on Sume, list x 1.25
    ("wan-3.0", "480p"): 0.0625, ("wan-3.0", "720p"): 0.125,
    ("wan-3.0", "1080p"): 0.25,
    ("seedance-2.5", "480p"): 0.269, ("seedance-2.5", "720p"): 0.578,
    ("seedance-2.5", "1080p"): 1.42155,
}
LIMITS = {"seedance-2.5": (4, 30), "wan-3.0": (2, 30)}

def price(model, res, seconds):
    lo, hi = LIMITS[model]
    if not lo <= seconds <= hi:
        raise ValueError(f"{model} takes {lo}-{hi} s")
    return math.ceil(RATE[(model, res)] * seconds * 100 - 1e-9) / 100

def guard(model, res, seconds, cap_usd):
    p = price(model, res, seconds)
    if p > cap_usd:
        raise SystemExit(f"refused: ${p:.2f} > cap ${cap_usd:.2f}")
    return p

print(guard("seedance-2.5", "720p", 30, 20.0))  # 17.34
print(guard("wan-3.0", "1080p", 30, 20.0))      # 7.5

Why a guard at all

A copied prompt with the wrong resolution is the usual cause. The same 30 seconds is $8.07 or $42.65 on the same model, a factor of more than five. Put the cap in config, log every refusal, and let a person raise it deliberately.

Pair it with GET /v1/models style discovery: read supported_durations and supported_resolutions from GET /v1/videos/models so that the guard also rejects a 31-second request. Seedance 2.5 accepts 4 to 30 seconds and Wan 3.0 accepts 2 to 30.

What the guard cannot know

It does not know your balance, your plan's queue, or later rate changes. After the job, usage.cost on the poll response is the Sume billable amount, which is the number to reconcile your estimate against.

Where to keep the numbers

Hard-coded rates age. Treat the dictionary as a seed and refresh it from the video models listing, which returns prices alongside capabilities, whenever your deploy runs. A mismatch between your table and the listing should fail a test, not silently pass a bad estimate.

Also keep the cap per environment. A cap of $20 is sensible for a human trying a prompt and wrong for a nightly batch; the batch should have its own total budget, checked before the first submit.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume