Stop an Omni draft batch at $5: sum usage.cost from each poll
A Python loop that submits 360p Omni drafts one at a time, adds the Sume usage.cost of each finished job, and stops before the next one would cross a $5 cap.

To stop an Omni draft batch at $5 on Sume, submit one job at a time, wait for it, add its usage.cost to a running total, and skip the next submit when the total plus the next job's estimate would pass the cap. The poll response of /v1/videos reports usage.cost as the Sume billable amount. A 10-second 360p draft is about $0.375 in the worked example below, so $5 buys about 13 of them.
Why one at a time
At submit, Sume reserves the estimated amount, and a successful completion captures it (Sume docs: Generation admission, read 2026-10-05). If you submit 40 drafts at once, 40 reservations are open at once, and the cap is not yours to enforce in code. A sequential loop gives the cap a meaning. It costs wall-clock time; Google's 360p draft mode is described as up to 60% faster than 720p, which helps (Google, read 2026-10-05). If you need parallel drafts, bound the fan-out by the cap divided by the per-job estimate.
The loop
EST is the per-job estimate you set from the catalog. The example uses $0.375 for 10 seconds at 360p; replace it with the live number.
Where the cap number comes from matters. Pick it from the budget for the whole project, then split it: drafts first, finals second. A common split is to spend at most a third of the cap on drafts, because Google describes the 360p mode as a third of the cost of standard 720p, so the draft pass of an entire storyboard should be small beside the finals.
Treat the estimate constant as a placeholder. Read the live per-second rate for the model and resolution from GET /v1/videos/models and multiply by the clip length before the loop starts, so a price change does not silently move your cap.
Last, handle errors. A 402 means the balance cannot cover the reservation, and a 429 means a queue or rate limit. Neither is a reason to retry in a tight loop. Stop the batch on 402, and wait and retry once on 429 with the same Idempotency-Key, which replays the original job if the first call actually landed.
Print the running total on every line, as the loop does. When a batch stops early, the last line is your report: how many drafts you got, and how much of the cap is left for finals.
import os, time, requests
URL = "https://api.sume.com/v1/videos"
AUTH = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
CAP, EST = 5.00, 0.375
prompts = ["A kettle boils on a stove", "Rain on a window at night",
"A cyclist crosses a bridge at dawn"]
spent = 0.0
for i, p in enumerate(prompts):
if spent + EST > CAP:
print("cap reached, stopping at", i)
break
body = {"model": "gemini-omni-flash-1.1", "prompt": p,
"resolution": "360p", "duration": 10, "aspect_ratio": "16:9"}
job = requests.post(URL, json=body,
headers={**AUTH, "Idempotency-Key": f"batch-{i}-v1"}).json()
while True:
s = requests.get(job["polling_url"], headers=AUTH).json()
if s["status"] in ("completed", "failed", "cancelled"):
break
time.sleep(5)
spent += (s.get("usage") or {}).get("cost", 0) or 0
print(i, s["status"], round(spent, 4))What the total means
A guard in your code is not a platform limit. If you want a hard spend limit on the Sume side, the MCP tools offer max_spend_usd on paid calls; for plain REST, this loop and a low balance are your controls.
- A failed or cancelled job is refunded, so it adds nothing you owe. The loop adds whatever
usage.costreports. - The loop's total is Sume's billable amount, not the provider's price. For the account-level view,
GET /v1/usage?job_id=...folds every ledger row for one job into asummary(Sume docs: Usage, read 2026-10-05). - A crash mid-loop loses the running total. Write it to a file after each job, and use the batch index in the Idempotency-Key so a restart does not double-submit job 3.
Sources
Related posts
More in Developers
- Can Strands Decider 2B pick which Sume MCP tool to call?
Strands Decider 2B scores options you give it. Build them from Sume's tools_list, then check the pick with tools_schema and dry_run before any paid call.
- Stripe allows 16 webhook endpoints; Sume takes a webhook URL per job
Stripe registers up to 16 endpoints. Sume has no registry: each job or Format run item carries its own public HTTPS webhook_url, signed with one secret.
- Stripe events arrive out of order; Sume sends only terminal job events
Stripe does not order events and says to dedupe on event ID. Sume sends only terminal job events keyed by job_id, so order rarely matters. Fetch state.
- Stripe retries webhooks for 3 days, Sume job webhooks for 4.5 minutes
Compare retry windows: Stripe live mode retries up to three days; Sume job webhooks use 10 attempts at 30s spacing. Size your poll fallback to the shorter one.
Written by Sume