Missed an agent run webhook? Poll status_url, redeliver is Format-only

Sume's docs describe a webhook redeliver route for Format runs. For an Agent Completion you did not get a POST for, read the run from its status or result URL.

5 min readSume
All posts

If an Agent Completion's webhook never arrived, read the run from its receipt URLs. The run webhook docs describe POST /v1/format-runs/{run_id}/webhook/redeliver, which needs the formats:write scope, for Format runs. I could not find a matching route for Agent Completions in those docs, so this post does not assume one. A delivery problem does not change the run: the docs say to fetch the run from result_url (Run webhooks).

What the docs say about missed deliveries

Sume makes up to 10 attempts per run, with backoff of min(max(30s x 2^(attempt-1) with jitter, Retry-After), 1h), then marks webhook_delivery.status as exhausted. If an endpoint rejects all ten attempts, you have a failed delivery and a run that is still completed.

The receipt's webhook_delivery object describes the delivery row. Read it to learn whether delivery succeeded, was exhausted or never started.

Recovering a missed run webhook, read 2026-10-05
SituationWhat to doSurface
Delivery exhaustedRead the run; it is still completestatus_url or result_url
Endpoint was downPoll the run for its terminal statusstatus_url
Format run, want a replayPOST webhook/redeliver with formats:writeFormat runs
Agent Completion, want a replayNot documented; poll insteadAgent runs
Canceled runNo webhook by design; poll statusstatus_url

A recovery decision

The function below picks the action from a receipt-shaped dictionary. The webhook_delivery field names follow the docs. It runs offline.

def next_step(run: dict) -> str:
    status = run.get("status")
    wd = run.get("webhook_delivery") or {}
    if status in ("queued", "processing"):
        return "poll status_url"
    if status == "canceled":
        return "done: cancel sends no webhook"
    if wd.get("status") == "exhausted":
        return "read result_url; delivery gave up"
    return "handle receipt"

if __name__ == "__main__":
    print(next_step({"status": "processing"}))
    print(next_step({"status": "completed",
                     "webhook_delivery": {"status": "exhausted"}}))
    print(next_step({"status": "canceled"}))

Design for a missing webhook

Treat the webhook as a convenience, not the source of truth. The docs say you still get status_url and result_url and can still poll. A webhook only saves you from running a loop for each run.

So run a slow sweeper: list recent runs with GET /v1/agent-runs, which returns newest first, and check any run that has been non-terminal longer than you expect. That closes the gap for every cause of a missed POST, from your own deploys to network trouble.

Which URL to read

An Agent Completion receipt includes status_url for polling and result_url for the finished result. Polling GET /v1/agent-runs/{id} needs the agent_completions:read scope. Keep the run id from the 202 receipt in your own store at submit time, so a lost webhook never leaves you without a handle.

Back off between polls. A run that is queued or processing can take a while, and the receipt's next_action field tells you to keep polling. Stop as soon as the status is completed, failed or canceled, and read the final receipt once.

Checklist

Keep these in your runbook.

  • Never re-submit a completion because a webhook was late.
  • Poll with backoff, not in a tight loop.
  • Use the Format redeliver route only for Format runs.
  • Dedupe on request_id when a replay does arrive.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume