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
- 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.
- Sort Sume image models by created? The field is one shared value
GET /v1/images/models returns the same created timestamp for every model, so it cannot tell you which is newest. What to use instead, with a script to prove it.
- Sume SDK error.retryable: server flag first, status only as fallback
SumeApiError.retryable uses the error envelope's retryable flag when present and falls back to 408, 429 or 5xx otherwise. A 409 is never retried by status.
- Sume uploadFile with raw bytes needs a content type, or no request
uploadFile refuses a Uint8Array or ArrayBuffer without contentType and throws SumeUploadError at step create before any call. Pass a typed Blob or a MIME.
Written by Sume