Pientegra API
Backend-to-Backend API

Events & Replay

Webhook delivery ledger for listing events, filtering by status, and replaying DEAD or FAILED deliveries.

Webhook deliveries in Pientegra are backed by a durable outbox row. Partners use two endpoints to read and recover from this outbox:

  • GET /external/events lists all events in the caller's tenant and site scope.
  • POST /external/events/:id/replay requeues an event in DEAD, FAILED, or DELIVERED state.

This is analogous to Stripe events.list plus events.resend. It is the official way to recover events after webhook handler downtime without opening a manual ops ticket.

List events

GET /api/v1/external/events
DEAD events from the last 24 hours
curl "$PIENTEGRA_API_BASE/external/events?createdFrom=2026-04-27T00:00:00Z&deliveryStatus=DEAD&limit=100" \
  -H "Authorization: Bearer $PIENTEGRA_API_KEY"

Query parameters

ParameterTypeDescription
createdFromISO 8601Lower bound for event creation time, inclusive.
createdToISO 8601Upper bound, exclusive.
eventTypecomma-separatedExample: intent.approved,intent.rejected.
deliveryStatuscomma-separatedPENDING, DELIVERED, FAILED, DEAD.
cursoropaqueReturned from the previous response's nextCursor.
limitint1..100, default 50.

Response shape

{
  "data": [
    {
      "eventId": "019dd459-43c1-711c-9e38-76a3182f4185",
      "eventType": "intent.approved",
      "occurredAt": "2026-04-28T13:00:00.000Z",
      "deliveryStatus": "DELIVERED",
      "attempts": 1,
      "lastResponseStatus": 200,
      "lastError": null,
      "deliveredAt": "2026-04-28T13:00:00.412Z",
      "payload": {
        "intent": {
          "id": "01927b3c-...",
          "referenceNo": "5MDLZBFDY7",
          "externalUserId": "user-12345",
          "requestedAmount": "100000",
          "amount": "100000",
          "currency": "TRY",
          "status": "APPROVED"
        }
      }
    }
  ],
  "nextCursor": null
}

The payload field stores the same envelope your webhook handler saw in the HTTP body, excluding eventId, eventType, and occurredAt, which are exposed as separate fields. Replay does not generate a new body; the partner receives the same signed body again.

Replay an event

POST /api/v1/external/events/:id/replay

Requeues an event in DEAD or FAILED state. It is dispatched with the same eventId and the same Pientegra-Event-Id header, so the partner handler should treat it as a duplicate event and process it idempotently.

curl -X POST "$PIENTEGRA_API_BASE/external/events/019dd459-43c1-711c-9e38-76a3182f4185/replay" \
  -H "Authorization: Bearer $PIENTEGRA_API_KEY"
Response
{
  "eventId": "019dd459-43c1-711c-9e38-76a3182f4185",
  "deliveryStatus": "PENDING"
}

Replay eligibility

Current statusCan it be replayed?
PENDINGNo. It is already queued or in-flight, and returns 409.
DELIVEREDYes. The partner processes it as a duplicate.
FAILEDYes. It forces another attempt before the next scheduled retry.
DEADYes. This is the main recovery path after terminal failure.

After replay, the attempt counter is reset to 0 and the event starts a fresh 8-attempt cycle.

Recovery playbook

  1. Detect webhook handler downtime.
  2. List DEAD events with GET /external/events?deliveryStatus=DEAD&createdFrom=<incident_start>.
  3. Call POST /external/events/:id/replay for each event.
  4. Because the handler sees the same Pientegra-Event-Id, correct deduplication preserves idempotency and side effects run only once.

Events are durable. Partners can request historical replay at any time today; a future version may limit replay to events created within a recent retention window, such as the last 30 days.

On this page