Skip to main content

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
ParamDefault / limitMeaning
limitdefault 50, max 200Rows returned.
status—Filter: pending | in_flight | delivered | exhausted.
since—ISO 8601 datetime; only deliveries created at or after it.
200
{
"success": true,
"deliveries": [
{
"eventId": "evt_66a1f0c2d3e4f5a6b7c8d9e0",
"sourceLoanNumber": "LN-2026-0001",
"sequence": 4,
"type": "payment.collected",
"status": "delivered",
"attempts": 1,
"nextAttemptAt": null,
"deliveredAt": "2026-08-17T09:31:02.418Z",
"lastStatusCode": 200,
"lastError": null,
"replayedAt": null,
"createdAt": "2026-08-17T09:31:01.907Z"
}
]
}
FieldMeaning
eventIdThe event's id — the same value as the X-Fieldproof-Delivery header and your dedupe key.
sourceLoanNumber, sequence, typeFrom the event envelope.
statuspending (queued for a first or next attempt), in_flight (a POST is running now), delivered (you answered 2xx), exhausted (all attempts failed).
attemptsPOSTs made so far.
nextAttemptAtWhen the next attempt is due (pending rows).
deliveredAtWhen you answered 2xx.
lastStatusCode, lastErrorWhat your endpoint returned last time — HTTP status, or the transport error (timeout, TLS, DNS…).
replayedAtSet if you replayed it (below).
createdAtWhen the delivery was queued.

exhausted = the full retry ladder failed (0s → 30s → 2m → 10m → 1h → 6h → 24h, 7 attempts, ≈31 hours). The event stays replayable for 30 days.

:::tip Monitor it A five-minute cron that calls GET /webhooks/deliveries?status=exhausted&since=<last check> and pages your on-call is the alerting you should have. 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
200
{ "success": true, "status": "pending", "message": "<human-readable text>" }
  • Queues an immediate re-delivery of that event and resets its retry ladder — an exhausted row gets a fresh 7 attempts.
  • Works on delivered rows too (lost it after processing? replay it). Your receiver's eventId dedupe makes replays harmless by design.
  • If the row is already pending or in_flight, the response says so ("already queued") — nothing extra is scheduled.
  • Events that were never queued (emitted while you had no callback configured, or before you subscribed to that type) can be replayed too: the replay creates the delivery on demand from the event store and queues it. This needs an active callback now — otherwise 422 CALLBACK_NOT_CONFIGURED.
  • 404 DELIVERY_NOT_FOUND — no event with that eventId exists 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:

200
{
"success": true,
"delivered": true,
"statusCode": 200,
"latencyMs": 212,
"error": null,
"bodyExcerpt": "{\"ok\":true}"
}
  • delivered: false with statusCode / error filled in tells you exactly what your endpoint did (a 401 here almost always means the signature was verified against a re-serialised body or the wrong path — see the receiver contract).
  • The ping envelope has sourceLoanNumber: null and sequence: 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.