Retries & DLQ

Delivery retries, dead-letter queue, and re-enqueue.

payzum retries failed webhook deliveries automatically and surfaces undeliverable messages in a dead-letter queue (DLQ) accessible from the admin.

When IPNs fire

Payment IPNs are sent when:

  • the invoice is paid (paid/overpaid, delivered as payment_status: "finished" — overpayment is normalized; detect it via actually_paid > pay_amount), or
  • the invoice expires (payment_status: "expired", including abandoned pay_currency: "all" drafts).

Informational deliveries also fire on wrong_token_received, suspicious_token_received, and late_deposit_received with the same payload shape. No IPN fires today on partial payment (partially_paid) or cancellation (cancelled/failed) — poll GET /v1/payment/:id for those; a partial-payment IPN is on the roadmap.

Retry policy

The retry policy differs by webhook type:

| | Payment IPN | Mass-payout webhook | |--|-------------|---------------------| | Max attempts | 5 | 5 | | Backoff | 30 s (fixed) | 60 s (fixed) | | Total budget | ~2 minutes | ~5 minutes | | Timeout per attempt | 10 s | 15 s |

Every delivery attempt — success or failure — is recorded with its attempt count, the HTTP status your endpoint returned, and your endpoint's response body. You can review this history for any invoice in your dashboard.

Retry vs. drop

The two channels handle failures differently:

| Your response | Payment IPN | Mass-payout webhook | |---------------|-------------|---------------------| | 2xx | Delivered; no further attempts | Delivered; no further attempts | | 5xx | Retried | Retried | | 4xx | Retried (any non-2xx is retried until attempts are exhausted) | Dropped immediately (treated as merchant misconfiguration) | | Timeout / network error | Retried | Retried |

For payment IPNs, every failure — including 4xx — is retried until the 5 attempts run out, after which the delivery lands in the DLQ. For mass-payout webhooks, a 4xx drops the delivery immediately; only 5xx and network errors are retried. Design your handler to be idempotent so replays are safe (see below).

Failed deliveries

After 5 failed attempts, payzum stops retrying and marks the delivery as failed. Failed deliveries are listed in your dashboard under the merchant's webhook (IPN) deliveries, each showing the attempt count, the last HTTP status, and the response body your endpoint returned — so you can diagnose why your handler rejected them.

Replaying a delivery

Once your endpoint is healthy again, you can replay a failed delivery from your dashboard. payzum re-attempts it as a fresh delivery.

Because a replay (or a normal retry) can cause the same event to arrive more than once, keep your handler idempotent — see the recommendations below.

Idempotency recommendations

Design your IPN handler to be idempotent. The same event may arrive more than once — either from retries or from a replay. Deduplicate on event_id for payment IPNs (or, as a legacy fallback, on payment_id + payment_status), and on eventId / the X-Payzum-Event-Id header for mass-payout webhooks, before taking any action.

  • Check whether the transition was already processed in your database before updating order state.
  • Avoid charging customers or releasing goods based on the delivery count — rely on the payment status fields.
  • For mass-payout handlers, store each processed eventId and skip duplicates.

The naming difference is intentional per surface: payment IPNs use snake_case (event_id, event_at) to match the payment object, while mass-payout webhooks use camelCase (eventId, eventAt) as a payzum-native format.