Count Sume bulk webhooks to know the queue is done, and the trap
A Sume bulk queue has no webhook, so some teams count per-item deliveries. Canceled and skipped runs never deliver, so a pure counter can hang. Use a hybrid.

Can you tell a Sume bulk queue is done by counting webhooks? Only as a fast path. The Bulk runs docs say the queue object has no webhook, and that communication.webhook_url is per item. The run webhook docs add the catch: a canceled run does not deliver a webhook, and a skipped run never delivers one either. A counter that waits for N deliveries from N items therefore never reaches N if even one child was canceled.
The fix is a hybrid: let webhooks update the counter early, and let one slow poll of the queue be the authority.
Rules for the counter
- Key the counter on
request_id, which equals the run id, so a retried delivery is counted once. - Order events by
created_at, not arrival time; delivery is retried up to 10 times. - Treat a webhook as a hint. The queue's
statusbecomingcompleted(every item terminal) is the only completion signal. - Remember a child skipped by the bulk controller is recorded as
failedin the queue, and a child canceled iscanceled.
Why not just poll
You can, and for many jobs you should: one read of the queue tells you everything. Item webhooks earn their place when you want to act on each video as it lands, for example to publish it or to update a row in your catalog. The counter in this post is for the case where you also want to know the batch is done without waiting for the next poll.
The failure to avoid is the silent one: a job that waits for N events from N items, where one item was canceled or never started. The docs say a child that fails to start has run_id: null and an error on the queue item, so it too will never send a webhook. Only the queue's own status can tell you that it is over.
A counter with a poll backstop
This class counts unique deliveries and finishes when either the count hits the item total or a queue read says completed. Both inputs are simulated, so it runs as is.
class QueueDone:
def __init__(self, total):
self.total, self.seen = total, set()
def on_webhook(self, request_id):
self.seen.add(request_id)
def done(self, queue_status=None):
if queue_status == "completed":
return True
return len(self.seen) >= self.total
q = QueueDone(total=3)
for rid in ["a", "b", "b"]: # duplicate delivery of b
q.on_webhook(rid)
print(q.done()) # False: c was canceled, no webhook
print(q.done(queue_status="completed")) # True after a queue readPoll cadence
Read the queue on a slow timer, for example once a minute with backoff on 429 and 503, not on every webhook. Polling spends the read budget, which the docs say is separate from the write budget used by create, so a gentle loop costs little. When the queue is completed, branch on counts.failed and counts.canceled, and fetch any missing receipts from GET /v1/format-runs/{run_id}.
If you set item webhooks at all, run the test delivery endpoint against the receiver first, and keep the signing secret out of source control. A receiver that refuses an empty secret fails closed, which is what you want in a counter that gates a publish step.
Sources
Related posts
More in Developers
- Run sume doctor --agent --json as a CI preflight and keep the output
sume doctor --agent --json checks local CLI readiness without calling the API. Run it before job steps, fail on bad JSON or a nonzero exit, and keep the file.
- Sume Format run status is spelled canceled with one L: fix your switch
A Format run ends as completed, failed, canceled or skipped. If your code matches cancelled with two Ls, a canceled run will look like it never ended.
- Sume Free plan and Omni: one running, five queued, seventh gets 429
On a Sume Free workspace one video job runs and five wait; a seventh submit returns 429 queue_full. What that means for an Omni test batch and its cost.
- Sume image 400s name the valid values: retry in code
Sume's Image API 400 bodies carry details.supported, allowed, min and max. A tested error table and a small function that retries with a valid value.
Written by Sume