Delivery log & replay
No support ticket needed to answer "did you send it?" — your webhook delivery history is queryable, and any delivered or failed event can be re-sent, via the API itself. This is also how you monitor your integration: the platform does not send alerts to your technical contact for exhausted deliveries or a circuit-breaker trip, so poll this endpoint (or the poll API) from your side.
Inspect deliveries
GET /api/v1/partner/webhooks/deliveries?limit=50
GET /api/v1/partner/webhooks/deliveries?status=exhausted&since=2026-08-10T00:00:00Z
| Param | Default / limit | Meaning |
|---|---|---|
limit | default 50, max 200 | Rows returned. |
status | — | Filter: pending | in_flight | delivered | exhausted. |
since | — | ISO 8601 datetime; only deliveries created (queued) at or after it — not delivered or exhausted after it. |
Rows come back newest first (by creation time).
{
"success": true,
"deliveries": [
{
"eventId": "evt_66a1f0c2d3e4f5a6b7c8d9e0",
"sourceLoanNumber": "LN-2026-0001",
"sequence": 4,
"type": "payment.collected",
"status": "delivered",
"attempts": 1,
"nextAttemptAt": "2026-08-17T09:31:01.907Z",
"deliveredAt": "2026-08-17T09:31:02.418Z",
"lastStatusCode": 200,
"lastError": null,
"replayedAt": null,
"createdAt": "2026-08-17T09:31:01.907Z"
}
]
}
| Field | Meaning |
|---|---|
eventId | The event's id — the same value as the X-Fieldproof-Delivery header and your dedupe key. |
sourceLoanNumber, sequence, type | From the event envelope. |
status | pending (queued for a first or next attempt), in_flight (a POST is running now), delivered (you answered 2xx), exhausted (all attempts failed — or, with lastError: "callback not configured/active" and typically attempts: 0, there was no active callback or no active key for this environment when it came due, so it was parked unsent; replay it once that is fixed). |
attempts | POSTs made so far. |
nextAttemptAt | When the next attempt is due (pending rows). It keeps its last value once a row is delivered or exhausted — ignore it then. |
deliveredAt | When you answered 2xx. |
lastStatusCode, lastError | What your endpoint returned last time — HTTP status, or the transport error (timeout, TLS, DNS…). |
replayedAt | Set if you replayed it (below). |
createdAt | When the delivery was queued. |
exhausted = the full retry ladder failed (0s → 30s → 2m → 10m → 1h → 6h → 24h, 7 attempts, ≈31 hours). Delivery rows are kept for 30 days
after they are delivered or exhausted; the event itself stays replayable for
≈13 months (below).
:::tip Monitor it
A five-minute cron that calls
GET /webhooks/deliveries?status=exhausted&since=<now − 48 h>&limit=200,
remembers the eventIds it has already alerted on, and pages your on-call
for new ones is the alerting you should have. Do not pass your last check
time as since: it filters on when the delivery was created, and exhaustion
comes ≈31 hours later, so that query never matches. Widen the window after a
circuit-breaker trip or a replay — both keep the original creation time and
push exhaustion later. lastError on the newest rows
tells you why (401 → your signature check, 5xx → your handler, timeouts →
respond faster). Quote the X-Request-Id response header when you write to
[email protected].
:::
Replay
POST /api/v1/partner/webhooks/deliveries/{eventId}/replay
{ "success": true, "status": "pending", "message": "<human-readable text>" }
- Queues an immediate re-delivery of that event and resets its retry
ladder — an
exhaustedrow gets a fresh 7 attempts. - Works on
deliveredrows too (lost it after processing? replay it). Your receiver'seventIddedupe makes replays harmless by design. - If the row is already
pendingorin_flight, the response says so ("already queued") — nothing extra is scheduled. - Events with no delivery row — emitted while you had no callback
configured, before you subscribed to that type, or whose row has aged out
after 30 days — can be replayed too: the replay creates the delivery on
demand from the event store (events are kept ≈13 months) and queues it.
This needs an active callback now — otherwise
422 CALLBACK_NOT_CONFIGURED. 404 DELIVERY_NOT_FOUND— no event with thateventIdexists for your organisation (wrong id, or another organisation's event).
A replay is an ordinary delivery — same event body and eventId, freshly
signed with a current timestamp — so your receiver needs nothing special. The
replay call itself counts toward your 60 requests/min API rate limit.
Test your endpoint
POST /api/v1/partner/webhooks/test
Fires a signed ping at your callback synchronously and returns the
result:
{
"success": true,
"delivered": true,
"statusCode": 200,
"latencyMs": 212,
"error": null,
"bodyExcerpt": "{\"ok\":true}"
}
delivered: falsewithstatusCode/errorfilled in tells you exactly what your endpoint did (a401here almost always means the signature was verified against a re-serialised body or the wrong path — see the receiver contract).- The
pingenvelope hassourceLoanNumber: nullandsequence: null— your receiver must tolerate that (full body). 422 CALLBACK_NOT_CONFIGURED— no active callback is registered for this environment (sandbox and production are configured separately).
Run it on every deploy of your receiver.