Sume webhook delivery statuses: pending to exhausted, and your move

A Sume job webhook has six delivery states, from pending to exhausted. What each means for your receiver, where to read it, and when to redeliver or poll.

5 min readSume
All posts

A Sume job webhook has a delivery status separate from the job status: pending, delivering, delivered, retrying, failed, or exhausted. The job can be completed while the delivery is exhausted, because the two are tracked on different objects. The practical rule is simple: a job result never depends on the delivery arriving, so a missing callback is a reason to poll, not a reason to resubmit.

The vocabulary comes from the Errors and rate limits page. The Webhooks page says the delivery status and attempt count show on the job object and in the job events when they are available.

The six values

The table lists the values exactly as the docs write them and adds what a receiver should do. The last two columns are my reading of the Webhooks page, not extra Sume fields.

Webhook delivery status vocabulary, as of 2026-10-09 (Errors and rate limits; Webhooks).
Delivery statusYour readingYour move
pendingA delivery is queued for the job's terminal eventNothing yet; the job may still be running
deliveringAn attempt is in flightBe ready to answer within 10 seconds
deliveredYour endpoint returned a 2xxStore the event by job_id once
retryingAn attempt failed; another is scheduledFix the receiver; Sume retries on its own
failedThe delivery did not succeedPoll status_url; redeliver after the fix
exhaustedAll automatic attempts are used (up to 10)Poll, or call redeliver for the job

Where to read it

The job object carries a webhook_delivery block, and the job events include webhook.delivery entries. The block holds the callback url, a last_error, and signing_secret_fingerprint. When a Studio Agent turn reads a job that another member created, url and last_error come back null, so the turn sees the state but not the owner's endpoint.

Reading the state is cheap, and reads have their own, larger rate-limit budget than writes. A reconciler that lists terminal jobs and checks their delivery state once a few minutes after completion is a reasonable pattern.

Redeliver after you fix the receiver

POST /v1/jobs/{job_id}/webhook/redeliver needs the jobs:write scope. Sume re-POSTs the real terminal event for that job with a fresh timestamp and signature, and the call still works after the automatic attempts are used up. It does not spend one of the ten automatic attempts, and it never changes the destination URL; a new URL means a new job.

Because the same job_id arrives again, the receiver must treat job_id as the idempotency key. The snippet calls the endpoint and prints the response.

const jobId = process.argv[2];
const res = await fetch(
  `https://api.sume.com/v1/jobs/${jobId}/webhook/redeliver`,
  {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
  },
);
console.log(res.status, await res.text());

Do not confuse it with Send test

Send test (POST /v1/webhooks/test-deliveries, needs account:write) posts a dummy signed webhook.test body to a URL you type. It never replays a real job and has no job_id. Use it to prove the URL and the signature check work; use redeliver to replay a real event.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume