Overview
Webhooks allow you to receive real-time notifications for payment events such as completion, failure, and refunds. ZAFA PAY sends HTTP POST requests to your registered webhook endpoints when payment status changes.Webhook endpoints can be managed from the Webhooks tab in the merchant dashboard (https://app.zafapay.com). Each endpoint has its own Webhook Secret for signature verification.
Webhook Endpoints
You can register multiple webhook endpoints to receive event notifications. Each endpoint has its own URL, secret, and optional event filter.| Feature | Description |
|---|---|
| Multiple endpoints | Register up to 16 webhook endpoints per merchant |
| Event filtering | Choose which event types each endpoint receives. If no filter is set, the endpoint receives all events |
| Per-endpoint secrets | Each endpoint has its own Webhook Secret (whsec_xxx format) for signature verification |
| Enable/disable | Endpoints can be individually activated or deactivated without deletion |
Event Types
| Event | Description |
|---|---|
payment.succeeded | Payment completed successfully |
payment.failed | Payment failed |
payment.canceled | Payment canceled |
payment.refunded | Refund completed |
payment.chargeback | Chargeback occurred |
Payload
Event type (e.g.,
payment.succeeded)Transaction ID
Merchant ID
Merchant name
Payment status (
succeeded, failed, canceled, refunded, chargeback)Payment amount (string format, e.g.,
"100.00")Currency code
Payment method (
card, depot, etc.)Saved card ID (
pmi_xxx format). Only included for recurring payments or when save_card was usedtrue for recurring (subscription) paymentsOnly included as
true when the card was saved for future useMerchant’s order ID (the value specified when creating the payment)
Product name (the value specified when creating the payment)
Customer ID (the value specified when creating the payment)
Customer’s email address (the value specified when creating the payment)
Customer’s phone number (the value specified when creating the payment)
Refunded amount (string format.
payment.refunded event only)Error message (
payment.failed event only)Card brand (
visa, mastercard, amex, jcb, etc.)Last 4 digits of the card number
Cardholder name
Card expiration month
Card expiration year
Metadata specified when creating the payment
Transaction creation timestamp (ISO 8601 format)
Webhook sent timestamp (ISO 8601 format)
Payload Examples
payment.succeeded (Payment Successful)
payment_method_idis only included whensave_cardwas used or for recurring paymentssave_cardis only included astruewhen the card was saved in the initial paymentis_recurringistruefor recurring payments
payment.failed (Payment Failed)
The
error field is only included in payment.failed events.payment.refunded (Refund Completed)
The
amount_refunded field is only included in payment.refunded events. For partial refunds, it shows the refunded amount.payment.chargeback (Chargeback Occurred)
Signature Verification
Webhook requests include a signature header. Verify this signature using the endpoint’s Webhook Secret to confirm the request was sent by ZAFA PAY.Signature Header
| Environment | Header Name |
|---|---|
| Sandbox | X-Zafapay-Signature-Sandbox |
| Production | X-Zafapay-Signature |
Verification Method
The signature is an HMAC-SHA256 hash of the request body (JSON string), using the endpoint’s Webhook Secret as the key.Node.js
Response
Return HTTP status code2xx when the webhook is successfully received.
Retry
ZAFA PAY automatically retries webhooks in the following cases:- HTTP status code other than
2xxis returned - Connection timeout occurs (10 seconds)
Retry Schedule
| Attempt | Delay After Failure |
|---|---|
| 1st | Immediate |
| 2nd | 1 minute later |
| 3rd | 5 minutes later |
| 4th | 30 minutes later |
| 5th | 2 hours later |
| 6th | 6 hours later |
Best Practices
Ensure Idempotency
The same event may be sent multiple times. Use
transaction_id as a key to prevent duplicate processingReturn Response Quickly
Process webhooks asynchronously and return
200 immediately. Long processing times will cause timeout retries