Python: turn a product CSV into Sume bulk Format queues
A short Python script splits a product manifest into batches of 100, builds one bulk body per batch with per-item spend caps, and keeps idempotency keys stable.

Split your manifest into slices of at most 100 rows, build one body per slice with concurrency and a per-item generation_spend_cap_usd, and send each with its own stable Idempotency-Key. The script below does that with the standard library only. It prints the slice sizes so you can run it without a key, and the submit call is where the real request goes.
import json, os, urllib.request
URL = "https://api.sume.com/v1/formats/sume/sume-product-commercial/bulk-runs"
def chunks(rows, size=100):
for i in range(0, len(rows), size):
yield rows[i:i + size]
def body(batch, concurrency=4, cap=50):
return {"concurrency": concurrency, "items": [
{"instruction": r["brief"], "input": {"sku": r["sku"]},
"generation_spend_cap_usd": cap} for r in batch]}
def submit(batch, key):
req = urllib.request.Request(URL, json.dumps(body(batch)).encode(), {
"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
"Content-Type": "application/json", "Idempotency-Key": key})
with urllib.request.urlopen(req) as res:
return json.load(res)["data"]["status_url"]
rows = [{"sku": f"A{n}", "brief": f"15s ad for item {n}"} for n in range(250)]
for i, batch in enumerate(chunks(rows)):
print(i, len(batch)) # swap for submit(batch, f"fall-promo-{i}")What the script does
chunkscuts the list at 100, the maximum number of items a bulk queue accepts.bodybuilds the envelope, which has only two keys:concurrency(1 to 16) anditems. Each item is the same body as a single Format run, here aninstruction, aninputobject you shape yourself and a cap.submitposts it withAuthorization: Bearerand anIdempotency-Key, then returns thestatus_urlfor polling.- The key is built from a label and the slice index, so rerunning the same manifest replays the same queue rather than creating a second one.
Rules the server enforces
Validate on your side first. The cheapest failure is the one that happens before a request: drop rows with an empty brief, make sure each item names at least one of the four accepted fields, and keep each input under the 2 MiB limit.
| Mistake | Response |
|---|---|
items empty or longer than 100 | 400 invalid_request |
concurrency outside 1 to 16 | 400 invalid_request |
An item with no instruction, input, previous_run_id or attachments | 400 invalid_request with details.index; no queue is created |
| Same key, different payload | 409 idempotency_conflict |
| Same key, same payload | 202 and the existing queue |
Key without formats:write | 403 insufficient_scope |
Make the input shape yours
input is a free-form object of up to 64 top-level keys and 2 MiB. The Format reads the keys it knows and the instruction wins where the two disagree. Read the Format first with GET /v1/formats/sume/{slug} to see its description and io profile, and put stable guidance in the instruction while row data goes in input.
After the submit
Store the queue id or status_url per slice, since there is no endpoint that lists queues. Poll until status is completed, then read counts.failed. For each item that has a run_id, fetch GET /v1/format-runs/{run_id} for the output. Items that failed before starting have run_id: null and an error code on the queue item itself.
Sources
Related posts
More in Formats
- Bulk queue concurrency 16 on Sume is a window, not a speed promise
Sume bulk Format runs accept concurrency 1 to 16. It limits how many children start at once and does not promise throughput. What 100 ad items really do.
- A Sume bulk queue item failed: read the child receipt first
A Sume queue item only says format_run_failed. Open the child run by run_id, compare spend to the cap, read output_error, then retry with previous_run_id.
- 100 Omni proofs, then 20 finals: two bulk queues cost $45, not $112.50
Run 100 weekly ad proofs at 360p in one Sume bulk queue, approve 20, then queue those at 1080p. Video cost: $22.50 plus $22.50 instead of $112.50.
- Cancel one episode in a running Sume bulk queue: what it frees
There is no cancel-queue endpoint on Sume. Cancel one item run and its slot frees for the next episode. A canceled run delivers no webhook; read cancel_effect.
Written by Sume