Skip to main content

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 URL when payment status changes.
The Webhook Secret can be found in the “Merchant Settings” section of the merchant dashboard (https://admin.zafapay.com).

Event Types

EventDescription
payment.succeededPayment completed successfully
payment.failedPayment failed
payment.canceledPayment canceled
payment.refundedRefund completed
payment.chargebackChargeback occurred

Payload

event
string
Event type (e.g., payment.succeeded)
transaction_id
string
Transaction ID
status
string
Payment status (succeeded, failed, canceled, refunded, chargeback)
amount
number
Payment amount
currency
string
Currency code
payment_method
string
Payment method (card, depot, etc.)
merchant_order_id
string
Merchant’s order ID (the value specified as external_id when creating the payment)
product_name
string
Product name (the value specified when creating the payment)
customer_id
string
Customer ID (the value specified when creating the payment)
email
string
Customer’s email address (the value specified when creating the payment)
tel
string
Customer’s phone number (the value specified when creating the payment)
amount_refunded
number
Refunded amount
created_at
string
Transaction creation timestamp (ISO 8601 format)
timestamp
string
Webhook sent timestamp (ISO 8601 format)

Payload Example

{
  "event": "payment.succeeded",
  "transaction_id": "tx_abc123",
  "status": "succeeded",
  "amount": 1000,
  "currency": "usd",
  "payment_method": "card",
  "merchant_order_id": "order_12345",
  "product_name": "Premium Plan",
  "customer_id": "cust_12345",
  "email": "customer@example.com",
  "tel": "09012345678",
  "amount_refunded": 0,
  "created_at": "2024-01-15T10:30:00Z",
  "timestamp": "2024-01-15T10:31:00Z"
}

Signature Verification

Webhook requests include a signature header. Verify this signature to confirm the request was sent by ZAFA PAY.

Signature Header

EnvironmentHeader Name
SandboxX-Zafapay-Signature-Sandbox
ProductionX-Zafapay-Signature

Verification Method

The signature is an HMAC-SHA256 hash of the request body (JSON string).
Node.js
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return signature === expectedSignature;
}

// Express.js example
app.post('/webhooks/zafapay', express.json(), (req, res) => {
  const signature = req.headers['x-zafapay-signature-sandbox'];
  const secret = process.env.ZAFAPAY_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process event
  const { event, transaction_id, status } = req.body;

  switch (event) {
    case 'payment.succeeded':
      // Handle successful payment
      break;
    case 'payment.failed':
      // Handle failed payment
      break;
    case 'payment.refunded':
      // Handle refund
      break;
  }

  res.json({ received: true });
});

Response

Return HTTP status code 2xx when the webhook is successfully received.
{
  "received": true
}

Retry

ZAFA PAY automatically retries webhooks in the following cases:
  • HTTP status code other than 2xx is returned
  • Connection timeout occurs
Retries are performed up to 3 times at intervals of 1 second, 2 seconds, and 3 seconds.

Best Practices

1

Always Verify Signature

Signature verification is essential to prevent unauthorized requests
2

Ensure Idempotency

The same event may be sent multiple times. Use transaction_id as a key to prevent duplicate processing
3

Return Response Quickly

Process webhooks asynchronously and return 200 immediately. Long processing times will cause timeout retries
4

Log Errors

Log received payloads and processing results for debugging