Worker crashed mid-poll: list Sume jobs and join on idempotency_key
After a restart, GET /v1/jobs?status=processing lists your in-flight video jobs. Each row carries the idempotency_key you sent, so match your records on it.

If a worker died after submitting Sume video jobs but before saving their ids, list the jobs with GET /v1/jobs?status=queued and status=processing and match each row to your own record by its idempotency_key. The list is newest first, capped at 100 per page, and an ordinary API key sees the jobs its owner created.
Do not match by position. The OpenAPI text says newest-first is not your submission order once a wave retries, and that the idempotency_key on each row is the column to join on.
The query parameters
These are the ones that matter for recovery. An unknown query parameter is a 400 unknown_parameter, not a silently unfiltered page.
| Parameter | Values | Use |
|---|---|---|
| status | queued, processing, completed, failed, canceled | one status per call |
| limit | 1 to 100 | page size |
| starting_after | the next_cursor from the last page | next page; absent cursor means done |
| scope | thread or workspace | an ordinary key defaults to its owner's jobs |
| type | any non-empty string | narrow by job type |
Walk the pages
Do not invent a cursor from the last job id. When data.next_cursor is missing you are on the last page. Run this with SUME_API_KEY set; it prints the id, status and key of every unfinished job.
import json, os, urllib.request
def page(status, cursor):
url = "https://api.sume.com/v1/jobs?limit=100&status=" + status
if cursor:
url += "&starting_after=" + cursor
req = urllib.request.Request(
url, headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]})
return json.load(urllib.request.urlopen(req))["data"]
def main():
for status in ("queued", "processing"):
cursor = None
while True:
data = page(status, cursor)
for job in data["jobs"]:
print(job["id"], job["status"], job["idempotency_key"], job["created_at"])
cursor = data.get("next_cursor")
if not cursor:
break
main()Why this replaces OpenAI's list call
OpenAI's video guide, read 2026-10-08, includes list and delete operations on videos, and the Videos API itself is removed on September 24, 2026. Sume's list is a read-only view over jobs of all kinds, not only video, so keep your own table as the source of truth and use the list for recovery.
Choose your Idempotency-Key from your record id at submit time, which makes this join possible; a random key per attempt leaves you with rows you cannot match. The storage post covers the columns to keep, and the list and delete post covers the removed routes.
Sources
Related posts
More in Developers
- H3 Max Recast prompt: 2,000 characters, and the fields Sume rejects
The optional Recast prompt is capped at 2,000 characters, and aspect_ratio, generate_audio and frame fields are refused. A checker to run before a paid submit.
- Recast prompt limit is 2,000 characters: what to write, what it costs
The H3 Max Recast prompt is optional and capped at 2,000 characters. See what to put in it for a person swap and why the length never changes the price on Sume.
- Reconcile a mixed project with GET /v1/usage: debited, held, refunded
How to read what one job or run really cost: debited, held and refunded fields, with the arithmetic for a project where one of six shots fails and is refunded.
- Refresh 1,200 SKU video ads before Black Friday: waves by plan
On an empty workspace, 1,200 jobs take 300 submission waves on Free, 67 on Pro and 14 on Scale, using Sume's wave_size_hint of 75% of accepted capacity.
Written by Sume