Webhooks
Webhooks
We POST signed JSON events to your webhook_url when payment state changes. Built for at-least-once delivery — your handler must be idempotent on event.id.
Envelope
{
"id": "evt_2x7Kq9_a1b2c3",
"type": "payment.succeeded",
"livemode": true,
"created_at": "2026-04-17T06:04:14Z",
"data": {
"payment_id": "cs_mo2hwnfb_044b0e14",
"session_id": "cs_mo2hwnfb_044b0e14",
"order_number": "order_2842",
"amount": 4900, "currency": "USD",
"status": "succeeded",
"payment_method": "card",
"card_last4": "1281", "card_brand": "mir",
"metadata": { "user_id": "u_842" },
"created_at": "2026-04-17T05:58:29Z"
}
}Headers we send
| Header | Description |
|---|---|
| X-MAXFI-Signature | sha256=<hex> — HMAC of raw body with your webhook secret. |
| X-MAXFI-Event | Convenience copy of event.type for routing. |
| X-MAXFI-Event-Id | Deduplication key — store this and skip replays. |
| X-MAXFI-Delivery | Per-attempt delivery id — useful in support tickets. |
| X-MAXFI-Attempt | 1-based retry counter. |
Event catalogue
| Type | When fires |
|---|---|
| payment.created | Session created. Useful for analytics + abandoned-cart recovery. |
| payment.requires_action | Customer reached 3DS challenge. We POST as soon as the redirect URL is available. |
| payment.processing | Acquirer accepted, waiting for issuer. |
| payment.succeeded | Money captured. Fulfil order on this event. |
| payment.failed | Declined. error_code + sanitized error_message included. |
| payment.cancelled | You called /cancel before capture, or session expired. |
| payment.refunded | Full or partial refund processed. Includes refund object + total_refunded. |
| refund.created | Refund initiated (sync ack from acquirer). |
| refund.failed | Refund rejected by acquirer (rare — usually concurrency). |
| payout.completed | Funds settled to merchant bank account. |
| payout.failed | Payout rejected. Check error_message + retry policy. |
| chargeback.created | Cardholder dispute opened. Ship evidence within deadline. |