Send more than 100 spreadsheet rows to a Sume Format in chunks
One Sume bulk queue takes 1 to 100 items. For a 450-row sheet, split it into chunks and key each chunk so a retry never doubles spend.

What do I do when my sheet has more than 100 rows?
POST /v1/formats/{handle}/{slug}/bulk-runs accepts items with 1 to 100 entries and a concurrency from 1 to 16. A 450-row sheet is therefore five queues: four of 100 rows and one of 50. Each item has the same body as a single run, so every row carries its own input, and optionally its own instruction or communication.webhook_url.
The queues are independent. Sume has no parent object tying them together, so your code owns the batch: the split, the keys, and the bookkeeping of which chunk got which queue id.
How do I make each chunk safe to retry?
Send an Idempotency-Key header per queue. A replay with the same payload returns 202 and the original queue instead of starting a second one. A different payload under the same key is a 409. The queue's key is scoped to your account and that Format, and the payload hash covers concurrency and items.
So the key should name the chunk and the sheet it came from. Hash the chunk's items into the key and an edited chunk gets a new key, while an unchanged chunk replays safely. If you would rather get the 409 as a guard against edits, leave the hash out and key on the batch id and chunk number alone.
import hashlib, json, os, requests
URL = "https://api.sume.com/v1/formats/acme/weekly-promo/bulk-runs"
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def chunks(rows, size=100):
for i in range(0, len(rows), size):
yield i // size, rows[i:i + size]
def submit(batch_id, rows, concurrency=4):
queues = {}
for n, part in chunks(rows):
items = [{"input": r} for r in part]
digest = hashlib.sha256(
json.dumps(items, sort_keys=True).encode()).hexdigest()[:12]
headers = {**H, "Idempotency-Key": f"{batch_id}-c{n}-{digest}"}
body = {"concurrency": concurrency, "items": items}
r = requests.post(URL, json=body, headers=headers, timeout=30)
r.raise_for_status()
queues[n] = r.json()["data"]["id"]
return queues
How should I set concurrency across chunks?
Run chunks one after another or in parallel, but remember the ceiling is your plan's generation concurrency: 1 on Free, 4 on Pro, 8 on Startup and 20 on Scale. Five queues each asking for 16 on a Pro workspace do not run 80 jobs at once; extra work waits for a slot.
A modest concurrency per queue, with queues submitted sequentially, keeps the order of completion predictable.
- Store the returned queue id next to the chunk number the moment the
202arrives. - Check
counts.failedon each queue, becausecompletedonly means every item is terminal. - Record the spreadsheet row range per chunk so item
indexmaps back to a row.
Sources
Related posts
- Bulk Format runs: 100 items, 16 at once, what completed means
- Format run retry: same key and body gives 200, changed body 409
- Retry failed items in an AI video batch: Sume bulk-run recovery
- Map Sume bulk queue results back to spreadsheet rows by item index
- Worst-case spend of a 100-item Sume bulk queue and its spend caps
More in Formats
- Spreadsheet with more than 64 columns: nest them in one Sume input key
A Sume run input allows 64 top-level keys and 2 MiB. Nested keys do not count toward the 64, so a 90-column sheet row fits under a single key.
- Stage a Sume Format change with no branches: second slug, If-Match
Sume Formats have no branches or revert. Test a change in a second Format slug, then promote it to the live one with a single If-Match PUT of the files.
- Stocking stuffer ads for 100 products: one bulk run, 16 at a time
One Sume bulk run takes 1-100 items and 1-16 parallel workers. Here is how to set it up for a stocking stuffer catalog and check the failed count at the end.
- Sume bulk item expires_at: 90 minutes start at dispatch, not at submit
A Sume run's expires_at is 90 minutes from created_at. A bulk child is created when dispatched, so a queued item's clock has not started.
Written by Sume