Page on-call when a Sume webhook is exhausted: PagerDuty dedup_key

Send a PagerDuty Events API v2 trigger when Sume gives up on a webhook, using the job id as dedup_key so retries and redelivers never page twice.

4 min readSume
All posts

Yes: you can page on-call when Sume stops retrying a webhook by sending a PagerDuty Events API v2 trigger event with the Sume job id as the dedup_key. PagerDuty's event endpoint is https://events.pagerduty.com/v2/enqueue, it answers 202 on success, and it returns the dedup key it used (read 2026-10-10).

Using the job id as the key gives you one alert per job no matter how many times you send it. That matters because Sume treats job_id as the idempotency key on its side too.

Why the job id is the right dedup key

Sume's webhooks page says a delivery gets up to 10 attempts, each timing out after 10 seconds, and that receivers should treat job_id as the idempotency key. After the last attempt, the delivery status is exhausted, one of the six states listed on the errors and credits page.

PagerDuty's page describes dedup_key as optional for trigger events and required for acknowledge and resolve (read 2026-10-10). If you set it yourself, a later resolve with the same value can close the alert you opened, so reuse the same job id when you redeliver and the delivery finally succeeds.

Field mapping, PagerDuty fields from its Events API v2 page (read 2026-10-10) and Sume fields from its webhooks docs
PagerDuty fieldValue to sendWhy
routing_keyYour Events API V2 integration keyRequired by PagerDuty; keep it in an environment variable
event_actiontrigger when exhausted, resolve after a successful redeliverAllowed values are trigger, acknowledge and resolve
dedup_keyThe Sume job_idOne open alert per job
payload.summaryShort text naming the job and the causeWhat the responder reads first
payload.sourceYour receiver or service nameIdentifies the sender

A sender that runs as written

This standard-library Python script triggers an alert for the job id passed on the command line. Set PAGERDUTY_ROUTING_KEY first. It sends the fields above, and PagerDuty's reply echoes the dedup_key it used.

import json, os, sys, urllib.request

def trigger(job_id, summary):
    body = {
        "routing_key": os.environ["PAGERDUTY_ROUTING_KEY"],
        "event_action": "trigger",
        "dedup_key": job_id,
        "payload": {"summary": summary, "source": "sume-webhook-receiver", "severity": "critical"},
    }
    req = urllib.request.Request(
        "https://events.pagerduty.com/v2/enqueue",
        data=json.dumps(body).encode(),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=10) as res:
        return json.load(res)

if __name__ == "__main__":
    print(trigger(sys.argv[1], "Sume webhook delivery exhausted for " + sys.argv[1]))

Where the trigger comes from

Sume does not push an event when it gives up, so something on your side has to notice. Two sources work. Poll the job object, which the docs say shows the webhook delivery status and attempt count when available, and trigger when it reads exhausted or failed. Or run a scheduled check for jobs that finished in Sume but never reached your receiver, which is the recovery path the webhooks page describes for missing events.

The receipt carries last_status_code and last_error, our transport error rather than your body, so copy them into payload.summary and the responder sees whether the cause was a refusal, a 10-second timeout or a redirect.

Close the loop with redeliver

Once the receiver is fixed, call POST /v1/jobs/{job_id}/webhook/redeliver with a jobs:write key. Sume re-sends the real terminal event with a fresh timestamp and signature, and this works after the ten automatic attempts are used. When your receiver stores the event, send a resolve event with the same dedup_key.

Keep the pager for the exhausted case only. Individual retrying states heal on their own within the retry schedule, and paging on them would wake someone for deliveries Sume is already handling.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume