Dead-letter & replay
A delivery that runs out of retries isn’t dropped — it’s dead-lettered: kept, fully inspectable, and replayable on demand. Every send attempt is recorded with its outcome, status code, and timing, so you can see exactly why a delivery failed and re-run it once the cause is fixed.
This is the never silently lost guarantee in practice. A failure is a row you can query, not an event you missed.
Find failed deliveries
Section titled “Find failed deliveries”List dead-lettered deliveries with the status filter:
curl -sS "https://api.schedstack.com/v1/deliveries?status=dead_letter" \ -H "Authorization: Bearer sk_test_…"{ "object": "list", "data": [ { "id": "dlv_01J9ZK3F8Q", "object": "delivery", "schedule_id": "sch_01J9ZK2A7B", "mode": "test", "status": "dead_letter", "scheduled_for": "2026-06-27T09:00:00Z", "deadline": "2026-06-27T10:00:00Z", "next_fire_at": null, "attempt_count": 8, "last_status_code": 500, "idempotency_key": "occ_01J9ZK2A7B_1", "replay_of": null, "created_at": "2026-06-27T09:00:00Z", "finalized_at": "2026-06-27T09:42:11Z" } ], "has_more": false, "next_cursor": null}Deliveries are returned newest-first. Combine filters to narrow the set:
status=— any delivery status:dead_letter,expired,succeeded,scheduled, and so on.schedule_id=sch_…— only deliveries from one schedule.created_after=/created_before=— RFC3339 timestamps to bound the window.cursor=/limit=— cursor pagination. Follownext_cursorwhilehas_moreis true (limitdefaults to 20; keep it at 100 or below).
curl -sS "https://api.schedstack.com/v1/deliveries?status=dead_letter\&schedule_id=sch_01J9ZK2A7B\&created_after=2026-06-27T00:00:00Z" \ -H "Authorization: Bearer sk_test_…"Inspect one delivery
Section titled “Inspect one delivery”Fetch a single delivery by id to see its final state and last response code:
curl -sS https://api.schedstack.com/v1/deliveries/dlv_01J9ZK3F8Q \ -H "Authorization: Bearer sk_test_…"attempt_count tells you how many times SchedStack tried; last_status_code is the code
from the final attempt. To see the full trail, list the attempts.
Read the attempt trail
Section titled “Read the attempt trail”Each delivery records every HTTP attempt. List them oldest-first:
curl -sS https://api.schedstack.com/v1/deliveries/dlv_01J9ZK3F8Q/attempts \ -H "Authorization: Bearer sk_test_…"{ "object": "list", "data": [ { "id": "att_01J9ZK3G10", "object": "attempt", "delivery_id": "dlv_01J9ZK3F8Q", "attempt_no": 1, "outcome": "retryable", "status_code": 503, "fired_at": "2026-06-27T09:00:00Z", "finished_at": "2026-06-27T09:00:00Z", "egress_ms": 214, "error": null }, { "id": "att_01J9ZK9H44", "object": "attempt", "delivery_id": "dlv_01J9ZK3F8Q", "attempt_no": 8, "outcome": "terminal", "status_code": 500, "fired_at": "2026-06-27T09:42:10Z", "finished_at": "2026-06-27T09:42:11Z", "egress_ms": 1180, "error": "upstream returned 500" } ], "has_more": false, "next_cursor": null}Each attempt’s outcome tells you what SchedStack did next:
success— your endpoint returned 2xx. The delivery is markedsucceeded; no more attempts.retryable— a408,429, or5xxresponse, or a transport fault (timeout, connection refused, DNS/TLS error), which SchedStack retried per the schedule’s backoff policy.terminal— no further attempt. Either a non-retryable response — any other4xx, a3xx(redirects are disabled), or a blocked/invalid target — which fails immediately on the first attempt, or a retryable failure that ran out of retries or budget (or whose TTL deadline passed). The delivery moved todead_letter/expired.
status_code is the HTTP status your endpoint returned (null if the request never
completed — a timeout or connection failure, with the cause in error). egress_ms is the
time SchedStack spent waiting on your endpoint for that attempt.
Replay a delivery
Section titled “Replay a delivery”Replaying creates a new delivery that re-sends the same occurrence, due immediately:
curl -sS -X POST \ https://api.schedstack.com/v1/deliveries/dlv_01J9ZK3F8Q/replay \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: $(uuidgen)"await fetch( "https://api.schedstack.com/v1/deliveries/dlv_01J9ZK3F8Q/replay", { method: "POST", headers: { "Authorization": `Bearer ${process.env.SCHEDSTACK_API_KEY}`, "Idempotency-Key": crypto.randomUUID(), }, },);import os, uuid, httpx
httpx.post( "https://api.schedstack.com/v1/deliveries/dlv_01J9ZK3F8Q/replay", headers={ "Authorization": f"Bearer {os.environ['SCHEDSTACK_API_KEY']}", "Idempotency-Key": str(uuid.uuid4()), },)You get back a fresh delivery (201 Created) whose replay_of points at the original. The
original is left untouched as the audit record:
{ "id": "dlv_01J9ZM0XYZ", "object": "delivery", "schedule_id": "sch_01J9ZK2A7B", "mode": "test", "status": "scheduled", "scheduled_for": "2026-06-27T11:05:00Z", "next_fire_at": "2026-06-27T11:05:00Z", "attempt_count": 0, "last_status_code": null, "idempotency_key": null, "replay_of": "dlv_01J9ZK3F8Q", "created_at": "2026-06-27T11:05:00Z", "finalized_at": null}Only terminal deliveries are replayable
Section titled “Only terminal deliveries are replayable”Replay is allowed only when the original is in a terminal state — dead_letter,
expired, succeeded, or canceled. A delivery that is still in flight
(scheduled, claimed, retry_scheduled, paused) returns 409 Conflict:
{ "error": { "type": "invalid_request_error", "code": "not_replayable", "message": "Delivery is not in a replayable (terminal) state.", "request_id": "req_01J9ZM10AB" }}Delivery status reference
Section titled “Delivery status reference”| Status | Terminal? | Replayable? | Meaning |
|---|---|---|---|
scheduled |
no | no | Waiting for its fire time. |
claimed |
no | no | A worker is sending it now. |
retry_scheduled |
no | no | A previous attempt failed; the next retry is queued. |
paused |
no | no | Held by a pause; not claimable. |
succeeded |
yes | yes | Your endpoint returned 2xx. |
dead_letter |
yes | yes | SchedStack gave up: retries exhausted, retry budget exhausted, or an immediate terminal failure (4xx/3xx/blocked target on attempt 1). |
expired |
yes | yes | Passed its ttl deadline before landing. |
canceled |
yes | yes | Canceled before it landed. |
Related
Section titled “Related”- Retries & backoff — how
retry_policy(max_attempts, backoff,ttl) decides when a delivery dead-letters. - MCP server — agents can list, inspect, and replay deliveries with the
replay_deliverytool, no glue code required. - Idempotency — how the outbound
Idempotency-Keyworks, and why a replay (which carries noidempotency_key) is delivered as a new logical request.