API referenceWebhook deliveries

Webhook deliveries

Read-only access to delivery attempt history for any of your webhook endpoints. Useful for debugging integration issues, reconciling missed events, and audit trails for compliance reviews.

The webhook_delivery object

{
  "object": "webhook_delivery",
  "id": "ckwhd_xxxxxxxxxxxx",
  "endpoint_id": "ckwhe_xxxxxxxxxxxx",
  "event_type": "payout_paid",
  "status": "delivered",
  "attempts": 1,
  "response_status": 200,
  "response_body": "{\"received\":true}",
  "error_message": null,
  "next_attempt_at": null,
  "delivered_at": "2026-05-05T12:34:56Z",
  "created_at": "2026-05-05T12:34:56Z"
}

Status values

StatusDescription
pendingQueued, awaiting first attempt
deliveredReceiver returned 2xx
failedReceiver returned non-2xx OR timed out — will retry
giving_upAll retry attempts exhausted (7 by default) — won’t retry again

GETList deliveries

GET/v1/webhook_deliveries
Query parameters
limitintegerOptional

1-100, default 50

starting_afterstringOptional

Cursor

endpoint_idstringOptional

Filter to one endpoint

statusstringOptional

Filter — pending | delivered | failed | giving_up

event_typestringOptional

Filter to one event type, e.g. payout_paid

Standard cursor-paginated list.

Request
# Recent failed deliveries on a specific endpoint
curl "https://api.swappr.me/api/v1/webhook_deliveries?endpoint_id=ckwhe_xxx&status=failed&limit=20" \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "object": "list",
  "has_more": true,
  "data": [
    { "object": "webhook_delivery", "id": "...", "status": "failed", ... },
    ...
  ]
}
200 OK

POSTReplay a delivery

POST/v1/webhook_deliveries/{id}/replay

Re-fires the event to the same endpoint the original delivery targeted (surgical — not a fan-out to every subscriber). It creates a new delivery attempt with its own id, signed with the endpoint’s current secret; the original delivery row is never mutated. Replay is allowed regardless of the original’s status (delivered, failed, giving_up, pending) — the intent is “re-fire this event”. On a failed re-attempt the new row is left retriable, so the standard webhook-retry path picks it up. The response’s replayed_from_id links back to the original delivery.

Requires the webhook_manage permission. Returns 400 if the endpoint is inactive, 404 if the delivery isn’t found.

Request
curl -X POST https://api.swappr.me/api/v1/webhook_deliveries/ckwhd_xxx/replay \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "object": "webhook_delivery",
  "id": "ckwhd_newattempt",
  "endpoint_id": "ckwhe_xxx",
  "event_type": "payout_paid",
  "status": "delivered",
  "attempts": 1,
  "response_status": 200,
  "error_message": null,
  "replayed_from_id": "ckwhd_xxx",
  "created_at": "2026-06-09T12:00:00.000Z",
  "delivered_at": "2026-06-09T12:00:00.420Z"
}

Common debugging flows

”Why didn’t I get a webhook for payout X?”

  1. List deliveries for that payout’s reference period:
    curl "https://api.swappr.me/api/v1/webhook_deliveries?event_type=payout_paid&limit=50" \
      -H "Authorization: Bearer sk_test_..."
  2. Look for the delivery with data.reference = po_xxx. Check its status and response_status.
  3. If failed or giving_up, the error_message + response_body will tell you why.
  4. Replay the delivery if needed — POST /v1/webhook_deliveries/{id}/replay (see Replay a delivery) or the dashboard’s per-delivery Retry button.

”Receiver is timing out”

Filter to status=failed and look at the error_message field. Common patterns:

  • Timeout after 10s — your handler is too slow. Acknowledge the webhook fast (within 5 seconds) and process async.
  • Connection refused / DNS error — your endpoint is down. Re-deploy + replay deliveries.

”Need a missed event for reconciliation”

Webhooks dropped after 7 retries land in giving_up status. The data is still queryable here — pull the body from data.payload (when admin tooling exposes it; the public API doesn’t expose payload to keep response sizes manageable).

Replay any delivery via POST /v1/webhook_deliveries/{id}/replay (see Replay a delivery) or the dashboard’s per-delivery Retry button.


Rate limits

This endpoint counts toward the read tier (120/min). Polling for status changes is fine, but use webhooks themselves as the primary signal — this endpoint is for retrospective debugging, not real-time feeds.