Sweep for missed Sume webhooks: list queued and processing jobs
A webhook is an optimization. Run a periodic sweep over GET /v1/jobs with status=queued and processing, then compare against your own records and re-check each.

Run a periodic sweep: list your non-terminal jobs with GET /v1/jobs?status=processing (and queued), compare them with the jobs your database thinks are finished, and read each stuck one from its status URL. The docs say a webhook is a delivery optimization and not your only recovery path, and a sweep is how you act on that.
Why a sweep and not just retries
Sume tries a webhook up to 10 times. After that you have a failed delivery and a job that still reached its real terminal state. Your receiver may also have stored nothing during an outage.
| Tool | Finds | Needs |
|---|---|---|
| Webhook retries | Terminal events during a short outage | Nothing |
Sweep over GET /v1/jobs | Jobs you lost track of | A scheduled task |
GET /v1/jobs/:id/status | One job's state | The job id |
| Webhook redeliver | Re-sends the real terminal event | jobs:write and a job with a webhook_url |
A paged listing
An API key lists the jobs its own member created in the workspace. Results are newest first, up to 100 per page, and data.next_cursor is passed back as starting_after.
import os, requests
BASE = "https://api.sume.com/v1/jobs"
HEADERS = {"Authorization": f"Bearer {os.environ.get('SUME_API_KEY', '')}"}
def list_jobs(session, status):
cursor = None
while True:
params = {"status": status, "limit": 100}
if cursor:
params["starting_after"] = cursor
r = session.get(BASE, headers=HEADERS, params=params, timeout=30)
r.raise_for_status()
data = r.json()["data"]
yield from data["jobs"]
cursor = data.get("next_cursor")
if not cursor: # absent on the last page
return
if __name__ == "__main__":
with requests.Session() as s:
for status in ("queued", "processing"):
for job in list_jobs(s, status):
print(job["id"], status, job.get("idempotency_key"))What to do with each row
- If a job is terminal in Sume and open in your records, read its result and close it.
- If it is still
processing, leave it alone and keep polling its status URL. - If you want the callback again, use Redeliver instead of resubmitting.
Sources
Related posts
More in Developers
- Test a Sume poll loop without waiting: inject sleep, assert delays
Unit test a job poll loop in milliseconds by injecting the fetch and the sleep. Assert that next_poll_after_seconds is obeyed and the 20-minute deadline holds.
- Text-to-speech API with curl and jq: one shell script to an MP3
Call the Sume TTS Router from a shell: submit with curl, loop on the status URL with jq until terminal, then download the audio artifact to voiceover.mp3.
- 30 image jobs in one async batch: submit in waves, poll, fetch results
A Python script that submits 30 Sume image jobs with mode async, keeps each SKU in metadata, polls the job status and reads artifacts from /v1/jobs/{id}/result.
- Timeline refuses more than 8 chained fades: fix a vertical montage
A Sume Timeline montage with nine fades in a row returns too_many_chained_transitions. Insert a hard cut and the 3-minute Short renders. Limits explained.
Written by Sume