Webhooks

Receive real-time notifications for events like payment completions.

What Are Webhooks?

Webhooks are automated messages sent from one server to another when a specific event occurs. In the context of CashPay, our servers will "push" a notification to an endpoint on your server (your `webhookUrl`) when a transaction's status changes.

This is the most reliable way to confirm a payment. While your customer is redirected back to your `redirectUrl` after payment, they might close their browser before this happens. A webhook ensures your backend is always notified, allowing you to reliably fulfill orders or grant access to services.

Securing Your Webhooks

To ensure that incoming webhook requests are genuinely from CashPay and not from a malicious third party, you must verify their signature. This is where your **API Secret** is used.

Signature Verification Flow

  1. CashPay sends a request to your webhook endpoint. The request includes a special header, `X-CashPay-Signature`.
  2. Your server receives the raw request body (as a string).
  3. Using your API Secret, you create a HMAC-SHA256 signature of the raw request body.
  4. You compare your generated signature with the one in the `X-CashPay-Signature` header.
  5. If they match, you can trust the request and process it. If not, you must discard it.

Pseudo-code for Signature Verification

JavaScript
const crypto = require('crypto');

// The secret you get from your dashboard
const cashpayApiSecret = process.env.CASHPAY_API_SECRET;

// The raw request body from the webhook
const requestBody = JSON.stringify(webhookPayload); 

// The signature sent in the request header
const signatureFromHeader = request.headers['X-CashPay-Signature'];

const generatedSignature = crypto
  .createHmac('sha256', cashpayApiSecret)
  .update(requestBody)
  .digest('hex');

if (generatedSignature === signatureFromHeader) {
  // The request is authentic, process it
  console.log('Webhook verified successfully!');
} else {
  // The request is not authentic, ignore it
  console.error('Webhook verification failed!');
}

Webhook Events & Payloads

Here are examples of the JSON payloads your webhook endpoint will receive for different events.

event: `payment.succeeded`

Sent when a payment initiated via the gateway is successfully completed.

Payload for a Successful Payment

JSON
{
  "event": "payment.succeeded",
  "data": {
    "reference": "ORDER-XYZ-123",
    "amount": 120.50,
    "currency": "USD",
    "status": "completed",
    "cashpay_transaction_id": "PAY_xxxxxxxxxxxx",
    "customer": {
        "name": "John Doe",
        "email": "john.doe@example.com"
    }
  }
}

event: `payment.failed`

Sent when a payment fails or is declined by the processor.

Payload for a Failed Payment

JSON
{
  "event": "payment.failed",
  "data": {
    "reference": "ORDER-XYZ-456",
    "amount": 55.00,
    "currency": "USD",
    "status": "failed",
    "failure_reason": "Insufficient funds."
  }
}

Responding to Webhooks

To acknowledge that you have received the webhook, your endpoint must return a `200 OK` HTTP status code. If our servers do not receive a `200 OK` response, we will retry sending the webhook several times over the next 24 hours.

It is important that your endpoint responds quickly. For long-running processes (like updating an order and sending an email), it's best practice to immediately respond with a `200 OK` and then handle the logic asynchronously in a background job.