Webhook dedupe id stable across retries: request_id and created_at
On Sume run webhooks, dedupe on the envelope request_id, which equals run_id and repeats on every retry. Order by created_at; request_id cannot.

On Sume run webhooks, dedupe on the envelope's request_id, which equals run_id and is stable across retries, and order deliveries by created_at. The same stability that makes request_id a good dedupe key is why it cannot order anything: every retry of a run carries the same value.
Which field does what?
| Field | Behavior | Use it for |
|---|---|---|
request_id | Equals run_id; stable across retries | Deduping |
run_id | The run this delivery is about | Deduping (same value) |
created_at | When this delivery body was built | Ordering deliveries |
payload.request_id | A correlation id for the call that produced the receipt | Ignore for dedupe |
Why can request_id not order deliveries?
Sume delivers one terminal event per run, and a failing endpoint gets up to 10 attempts. Each attempt for the same run carries the same request_id, so two deliveries cannot be told apart, let alone sequenced, by it. created_at is the field the docs point to for ordering.
What is the second request_id in the payload?
The receipt nested at payload.request_id is a correlation id for the call that produced it. It is the run id in a webhook, but an HTTP req_ id when you read the same receipt from GET /v1/format-runs/{run_id}. The docs say to dedupe on the envelope's request_id (or run_id) and ignore the nested one.
What about job webhooks?
Generation job webhooks carry a job_id instead, and the docs tell receivers to treat job_id as the idempotency key. A redeliver of a job re-sends the same real terminal event with a fresh timestamp and signature, so the dedupe key does not change while the signature does.
What else is on the envelope?
Two more fields decide what your handler does. status is OK or ERROR, but the docs say to branch on outcome (ok, degraded or error) when the question is whether you got usable output. payload is the run receipt and is null only on overflow.
How should the dedupe step be written?
Record the event durably, keyed by the envelope's request_id, then return a fast 2xx and do the work afterward. The Sume SDK example does exactly this: it calls recordTerminalRun(event.request_id, event) before returning 204. A second delivery for the same run then finds the key already present and returns 2xx without repeating side effects.
What happens with a redelivery?
A Redeliver re-POSTs the current terminal receipt with a fresh timestamp and signature, and it carries the same run. Dedupe on the run id keeps your side effects to one even though the signature and the request differ. Because the docs say request_id is stable across retries, treat any second delivery with a known request_id as a repeat, acknowledge it with 2xx, and skip the work.
Sources
Related posts
More in Developers
- Webhook retry: fixed delay vs exponential backoff, with numbers
Fixed delay retries at even gaps; exponential backoff doubles them. Sume uses fixed for job webhooks and backoff for run webhooks: how long each keeps trying.
- Webhook unknown event type: return 204, not a 500
One Sume verifier covers run and job webhooks. Route on event and answer 204 for unknown types so a new event never becomes a 500 and a retry storm.
- Webhook signature mismatch: compare the secret fingerprint first
When a Sume webhook signature will not verify, compare x-sume-webhook-secret-fingerprint with the dashboard fingerprint. It is safe to paste into a ticket.
- Webhook secret rotation: no downtime with a 24-hour window
After you rotate a Sume webhook signing secret, deliveries carry two signatures for 24 hours. What the header looks like and how to redeploy safely.
Written by Sume