Sume job webhook: request_id equals job_id, store one
In a Sume job webhook payload, request_id and job_id are the same value. Which to use as your dedupe key, and what else the payload carries.

In a Sume job webhook, request_id and job_id carry the same value, the job's id. Store job_id, not both, and dedupe on the pair of job_id and event so that retries and redeliveries collapse.
The payload shape is event, request_id, job_id, status, payload and, on failure, error. This matches the webhook code in the repo and the docs.
The fields
The three event names are job.completed, job.failed and job.canceled. Nothing else is sent.
| Field | Notes |
|---|---|
| event | job.completed, job.failed or job.canceled |
| request_id | Equal to job_id |
| job_id | The job's id; use it to read GET /v1/jobs/{id} |
| status | OK on completed; ERROR on failed or canceled |
| payload | Result on completed; null otherwise |
| error | Present on failed or canceled; absent on completed |
Dedupe key
Sume retries up to 10 times and a manual redeliver sends the same event again, so you will see duplicates. The key (job_id, event) is stable across them. A job can legitimately produce only one terminal event, but a redeliver repeats it, so use insert-or-ignore semantics instead of assuming first sight.
Do not rely on the payload alone
Use the webhook as a nudge. Read GET /v1/jobs/{id} when you need the current record, which stays correct even if you missed or reordered a delivery. Note that request_id here is not the error envelope's request id from API responses, which is a separate value you can log for support.
If you also log request ids from API responses for support, name the two clearly in your schema, for example webhook_job_id and api_request_id, so nobody joins them by mistake. The id in an error envelope or response header identifies one HTTP request and is useful when you ask for help. The job id identifies the unit of work and is what you poll, cancel and redeliver. A table with job_id as the primary key, a column for the last event seen and a column for when you fetched the artifacts is usually all the state a receiver needs.
Tradeoffs
Storing the whole payload keeps an audit trail but duplicates data you can refetch. Storing only job_id and event is lighter and sufficient if you always fetch the artifacts after.
One caution: that equality is how the webhook code builds the payload today. If you only ever use job_id, you are protected if the two ever differ, because job_id is the value every Sume job endpoint accepts.
Sources
Related posts
More in Developers
- Sume jobs list: no next_cursor on the last page ends the loop
GET /v1/jobs returns up to 100 jobs newest first. Pass data.next_cursor back as starting_after, and stop when it is absent. Do not build a cursor yourself.
- Sume GET /v1/jobs: a misspelled filter returns 400, not all jobs
Sume rejects an unrecognized query parameter on GET /v1/jobs with 400 unknown_parameter, so a typo cannot return an unfiltered page. Valid filters listed.
- Sume MCP tool names: tools.list or tools_list, which one to call?
Use the underscore ids from tools_list, like generate_image. Sume also accepts dotted aliases, but tools_schema wants snake_case and clients may add a prefix.
- A Sume poll returned HTML: guard the JSON parse in Python
A proxy or edge can answer a Sume poll with an HTML page. A tested stdlib Python helper that returns None for non-JSON bodies so your loop retries, not crashes.
Written by Sume