> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mavapay.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Examples

> Complete webhook payload examples for all supported currencies

# Webhook Payload Examples

This guide provides complete webhook payload examples for each supported currency. Mavapay sends webhooks for two main event types: `payment.received` (DEPOSIT) and `payment.sent` (WITHDRAWAL).

## Event Types

| Event                  | Type       | Description                                                |
| ---------------------- | ---------- | ---------------------------------------------------------- |
| `payment.received`     | DEPOSIT    | Triggered when Mavapay receives funds from a customer      |
| `payment.sent`         | WITHDRAWAL | Triggered when Mavapay sends funds to a beneficiary        |
| `payment_link.settled` | SETTLEMENT | Triggered when a Payment Link transaction is fully settled |

## Bitcoin (BTC) Webhooks

### payment.received (Deposit)

Triggered when Bitcoin payment is received via Lightning Network.

```json theme={null}
{
  "event": "payment.received",
  "data": {
    "id": "9830a229-1db0-4a19-9e51-37cca51586f2",
    "walletId": "98b5093f-6913-48c6-acb4-8fdc46c7feec",
    "ref": "678ae2e20de0dee7aecd2bd40f8c9",
    "hash": "6834d0d46ce47f0012cb36ca",
    "amount": 3427,
    "fees": 17,
    "currency": "BTC",
    "type": "DEPOSIT",
    "status": "SUCCESS",
    "autopayout": true,
    "createdAt": "2025-05-26T20:37:23.566Z",
    "updatedAt": "2025-05-26T20:37:23.566Z",
    "btcUsdMetadata": {
      "id": "698daefd-1dd8-4420-9c0a-5d78080d7c27",
      "orderId": "58772-8830",
      "paymentMethod": "BANKTRANSFER",
      "customerReference": "order-1234567890",
      "customerInternalFee": 0,
      "estimatedRoutingFee": 0,
      "onChainAddress": null,
      "lnInvoice": "lntbs34270n1p5rf5rlpp56xqq6cj9ml75v0yl6fsfrlmwfmaygnal8gd706l3epzethymhclsdz5296...",
      "lnAddress": null,
      "createdAt": "2025-05-26T20:37:23.576Z",
      "updatedAt": "2025-05-26T20:37:23.576Z"
    }
  }
}
```

### Key Fields

| Field                      | Description                         |
| -------------------------- | ----------------------------------- |
| `amount`                   | Amount in satoshis                  |
| `fees`                     | Transaction fees in satoshis        |
| `hash`                     | Payment hash for tracking           |
| `btcUsdMetadata.lnInvoice` | The Lightning invoice that was paid |
| `btcUsdMetadata.orderId`   | Associated order ID                 |

### payment.sent (On-Chain Withdrawal)

Triggered when Bitcoin is sent on-chain to a beneficiary address.

```json theme={null}
{
  "event": "payment.sent",
  "data": {
    "id": "220b23dc-38f7-413c-b2d1-b7f765c50add",
    "walletId": "40aa2b67-1498-449d-85f2-17b93eab2d74",
    "ref": "19d4793744af1e9fc77cb64d374d6",
    "hash": "691f836d4e7ce000125478be",
    "amount": 6000,
    "fees": 0,
    "currency": "BTC",
    "type": "WITHDRAWAL",
    "status": "SUCCESS",
    "autopayout": true,
    "createdAt": "2025-11-20T21:10:12.180Z",
    "updatedAt": "2025-11-20T23:35:52.986Z",
    "btcUsdMetadata": {
      "id": "b6d82314-0148-413e-bfad-ccd74a45969e",
      "orderId": "44092-3881",
      "paymentMethod": "BANKTRANSFER",
      "customerReference": "7e8cdec9-77c8-4bda-bf9f-2e96777b2c69",
      "customerInternalFee": 0,
      "lnInvoice": null,
      "lnAddress": null,
      "onChainAddress": "bc1q8yz7u50r4nne2q8wkuc4kyxx0s76fxsjlac5fxd8h7tzkh4rs82qnweuv5",
      "onchainTxid": "5c5df6db67a8fbe684d48560fe151a0ecfade509d640bd21b6a787707b972f62",
      "onchainNetworkSpeed": "medium",
      "createdAt": "2025-11-20T21:10:12.185Z",
      "updatedAt": "2025-11-20T23:35:53.036Z"
    }
  }
}
```

### On-Chain Specific Fields

| Field                                | Description                                              |
| ------------------------------------ | -------------------------------------------------------- |
| `btcUsdMetadata.onChainAddress`      | The Bitcoin address that received the payment            |
| `btcUsdMetadata.onchainTxid`         | The Bitcoin transaction ID (viewable on block explorers) |
| `btcUsdMetadata.onchainNetworkSpeed` | Fee priority used: `slow`, `medium`, or `fast`           |

<Note>
  On-chain withdrawals remain in `PENDING` status until there are **3 block confirmations**, after which the status changes to `SUCCESS`.
</Note>

## Payment Link Webhooks

### payment\_link.settled

Triggered when a Payment Link transaction is fully settled (after block confirmations for on-chain).

```json theme={null}
{
  "event": "payment_link.settled",
  "data": {
    "paymentRef": "1c50bb6a-9f49-493c-86b5-75a9e790f7c9",
    "paymentLink": "https://checkout.mavapay.co/1c50bb6a-9f49-493c-86b5-75a9e790f7c9",
    "callbackUrl": "https://your-app.com/callback",
    "settlementCurrency": "BTC",
    "paymentCurrency": "BTC",
    "paymentMethod": "BANKTRANSFER",
    "transaction": {
      "id": "220b23dc-38f7-413c-b2d1-b7f765c50add",
      "walletId": "40aa2b67-1498-449d-85f2-17b93eab2d74",
      "ref": "19d4793744af1e9fc77cb64d374d6",
      "hash": "691f836d4e7ce000125478be",
      "amount": 6000,
      "fees": 0,
      "currency": "BTC",
      "type": "WITHDRAWAL",
      "status": "SUCCESS",
      "autopayout": true,
      "createdAt": "2025-11-20T21:10:12.180Z",
      "updatedAt": "2025-11-20T23:35:52.986Z",
      "btcUsdMetadata": {
        "id": "b6d82314-0148-413e-bfad-ccd74a45969e",
        "orderId": "44092-3881",
        "paymentMethod": "BANKTRANSFER",
        "customerReference": "7e8cdec9-77c8-4bda-bf9f-2e96777b2c69",
        "customerInternalFee": 0,
        "onChainAddress": "bc1q8yz7u50r4nne2q8wkuc4kyxx0s76fxsjlac5fxd8h7tzkh4rs82qnweuv5",
        "lnInvoice": null,
        "lnAddress": null,
        "onchainTxid": "5c5df6db67a8fbe684d48560fe151a0ecfade509d640bd21b6a787707b972f62",
        "onchainNetworkSpeed": "medium",
        "createdAt": "2025-11-20T21:10:12.185Z",
        "updatedAt": "2025-11-20T23:35:53.036Z"
      }
    }
  }
}
```

### Key Fields

| Field                | Description                                         |
| -------------------- | --------------------------------------------------- |
| `paymentRef`         | Unique reference for the payment link               |
| `paymentLink`        | The checkout URL                                    |
| `callbackUrl`        | Your registered callback URL                        |
| `settlementCurrency` | The currency received (e.g., BTC)                   |
| `transaction`        | Full transaction details including `btcUsdMetadata` |

## Nigerian Naira (NGN) Webhooks

### payment.received (Deposit)

Triggered when NGN payment is received in your Mavapay account.

```json theme={null}
{
  "event": "payment.received",
  "data": {
    "id": "0b234e32-d5ba-4c2a-8f71-0b820a477f01",
    "walletId": "b7e7b823-b572-41d3-86a6-a6872f35c274",
    "ref": "f05432ecab06ca0357596af0366de",
    "hash": "001f7fb879bb3874eb057dcce06437d45d4020d7f348a36cd583b658e98e07d6",
    "amount": 300000,
    "fees": 2500,
    "currency": "NGN",
    "type": "DEPOSIT",
    "status": "SUCCESS",
    "autopayout": true,
    "createdAt": "2025-01-17T13:20:20.575Z",
    "updatedAt": "2025-01-17T13:20:20.575Z",
    "transactionMetadata": {
      "id": "570cba51-d9fd-402a-8b10-5c43e23077d8",
      "orderId": "82958-2591",
      "bankCode": "09026",
      "bankName": "KUDA MICROFINANCE BANK",
      "bankAccountName": "OLADEJI OLAOLU",
      "bankAccountNumber": "0123456789",
      "customerInternalFee": 0,
      "customerReference": "order-1234567890",
      "createdAt": "2025-02-03T14:18:20.737Z",
      "updatedAt": "2025-02-03T14:18:22.777Z"
    }
  }
}
```

### Key Fields

| Field                                   | Description                       |
| --------------------------------------- | --------------------------------- |
| `amount`                                | Amount in kobo (1 NGN = 100 kobo) |
| `fees`                                  | Transaction fees in kobo          |
| `transactionMetadata.bankAccountName`   | Sender's bank account name        |
| `transactionMetadata.bankAccountNumber` | Sender's account number           |
| `transactionMetadata.bankName`          | Sender's bank name                |

<Note>
  NGN amounts are in kobo. Divide by 100 to get the amount in Naira.
</Note>

## South African Rand (ZAR) Webhooks

### payment.sent (Withdrawal)

Triggered when ZAR payment is sent to a beneficiary.

```json theme={null}
{
  "event": "payment.sent",
  "data": {
      "id": "14cfbe34-91b3-45ef-b1b0-bc7d55df7f0f",
      "walletId": "99a8272d-c8d7-436b-952b-a13ef816df9c",
      "ref": "d386f2c1260d53ad60bead81e1c99",
      "hash": "08f7198fd7dd73c087b4754a20d6f63f5b87bb8fcdc10e4d5cacd27650fce2ba",
      "amount": 5000,
      "fees": 0,
      "currency": "ZAR",
      "type": "WITHDRAWAL",
      "status": "PENDING",
      "autopayout": true,
      "createdAt": "2025-01-30T15:23:06.097Z",
      "updatedAt": "2025-01-30T15:23:09.768Z",
      "zarTransactionMetadata": {
          "id": "7801c544-2f05-4914-91e1-d157848ac569",
          "customerReference": "7e8cdec9-77c8-4bda-bf9f-2e96777b2c69",
          "orderId": "47581-9962",
          "merchantName": "Ricki Allardice",
          "bankName": "CAPITEC BANK",
          "bankAccountNumber": "1352906218",
          "reference": "MPYMX76EvJD2FYmUAkNd",
          "customerInternalFee": 0,
          "createdAt": "2025-01-30T15:23:06.099Z",
          "updatedAt": "2025-01-30T15:23:09.772Z"
      }
  }
}
```

### Key Fields

| Field                                      | Description                         |
| ------------------------------------------ | ----------------------------------- |
| `amount`                                   | Amount in cents (1 ZAR = 100 cents) |
| `status`                                   | Can be PENDING, SUCCESS, or FAILED  |
| `zarTransactionMetadata.merchantName`      | Beneficiary name                    |
| `zarTransactionMetadata.bankAccountNumber` | Beneficiary account number          |
| `zarTransactionMetadata.reference`         | Unique transaction reference        |

<Note>
  ZAR amounts are in cents. Divide by 100 to get the amount in Rand.
</Note>

## Kenyan Shilling (KES) Webhooks

### payment.sent (Withdrawal)

Triggered when KES payment is sent via mobile money (M-Pesa or Airtel) or M-Pesa paybill/till.

```json theme={null}
{
  "event": "payment.sent",
  "data": {
      "id": "14cfbe34-91b3-45ef-b1b0-bc7d55df7f0f",
      "walletId": "99a8272d-c8d7-436b-952b-a13ef816df9c",
      "ref": "d386f2c1260d53ad60bead81e1c99",
      "hash": "08f7198fd7dd73c087b4754a20d6f63f5b87bb8fcdc10e4d5cacd27650fce2ba",
      "amount": 5000,
      "fees": 0,
      "currency": "KES",
      "type": "WITHDRAWAL",
      "status": "SUCCESS",
      "autopayout": true,
      "createdAt": "2025-01-30T15:23:06.097Z",
      "updatedAt": "2025-01-30T15:23:09.768Z",
      "kesTransactionMetadata": {
          "id": "7801c544-2f05-4914-91e1-d157848ac569",
          "customerReference": "7e8cdec9-77c8-4bda-bf9f-2e96777b2c69",
          "customerInternalFee": 0,
          "identifierType": "paytophone",
          "identifiers": {
            "phoneNumber": "+254796980711",
            "accountName": "Nambanja David",
            "network": "mpesa"
          },
          "createdAt": "2025-01-30T15:23:06.099Z",
          "updatedAt": "2025-01-30T15:23:09.772Z"
      }
  }
}
```

### Key Fields

| Field                                   | Description                                                                              |
| --------------------------------------- | ---------------------------------------------------------------------------------------- |
| `amount`                                | Amount in cents (1 KES = 100 cents)                                                      |
| `kesTransactionMetadata.identifierType` | Payment type (paytophone, paytobill, paytotill)                                          |
| `kesTransactionMetadata.identifiers`    | Payment details (varies by type; paytophone includes `network`: `"mpesa"` or `"airtel"`) |

<Note>
  KES amounts are in cents. Divide by 100 to get the amount in Shillings.
</Note>

## Ghanaian Cedi (GHS) Webhooks

### payment.sent (Withdrawal)

Triggered when GHS payment is sent via MTN Mobile Money.

```json theme={null}
{
  "event": "payment.sent",
  "data": {
      "id": "14cfbe34-91b3-45ef-b1b0-bc7d55df7f0f",
      "walletId": "99a8272d-c8d7-436b-952b-a13ef816df9c",
      "ref": "d386f2c1260d53ad60bead81e1c99",
      "hash": "08f7198fd7dd73c087b4754a20d6f63f5b87bb8fcdc10e4d5cacd27650fce2ba",
      "amount": 5000,
      "fees": 0,
      "currency": "GHS",
      "type": "WITHDRAWAL",
      "status": "SUCCESS",
      "autopayout": true,
      "createdAt": "2025-01-30T15:23:06.097Z",
      "updatedAt": "2025-01-30T15:23:09.768Z",
      "ghsTransactionMetadata": {
          "id": "7801c544-2f05-4914-91e1-d157848ac569",
          "customerReference": "7e8cdec9-77c8-4bda-bf9f-2e96777b2c69",
          "customerInternalFee": 0,
          "identifierType": "MTN",
          "identifiers": {
            "phoneNumber": "+233999992800",
            "accountName": "Mensah"
          },
          "createdAt": "2025-01-30T15:23:06.099Z",
          "updatedAt": "2025-01-30T15:23:09.772Z"
      }
  }
}
```

### Key Fields

| Field                                   | Description                             |
| --------------------------------------- | --------------------------------------- |
| `amount`                                | Amount in pesewa (1 GHS = 100 pesewa)   |
| `ghsTransactionMetadata.identifierType` | Mobile money network identifier (`MTN`) |
| `ghsTransactionMetadata.identifiers`    | Beneficiary payout details              |

<Note>
  GHS amounts are in pesewa. Divide by 100 to get the amount in Cedis.
</Note>

## Transaction Status Values

| Status    | Description                        |
| --------- | ---------------------------------- |
| `PENDING` | Transaction is being processed     |
| `SUCCESS` | Transaction completed successfully |
| `FAILED`  | Transaction failed                 |

## Handling Webhooks

### 1. Verify Webhook Signature

Always verify the webhook signature to ensure it's from Mavapay:

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}
```

### 2. Process Webhook Events

```javascript theme={null}
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-mavapay-signature'];
  const isValid = verifyWebhookSignature(
    req.body,
    signature,
    process.env.WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(400).json({ error: 'Invalid signature' });
  }

  const { event, data } = req.body;

  switch (event) {
    case 'payment.received':
      // Handle deposit
      handleDeposit(data);
      break;
    case 'payment.sent':
      // Handle withdrawal
      handleWithdrawal(data);
      break;
    default:
      console.log(`Unhandled event type: ${event}`);
  }

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

### 3. Implement Idempotency

Use the transaction ID to prevent duplicate processing:

```javascript theme={null}
function handleDeposit(data) {
  const { id, amount, currency, status } = data;
  
  // Check if already processed
  if (alreadyProcessed(id)) {
    console.log(`Transaction ${id} already processed`);
    return;
  }
  
  // Process the deposit
  processDeposit({ id, amount, currency, status });
  
  // Mark as processed
  markAsProcessed(id);
}
```

## Best Practices

1. **Respond Quickly**: Return a 200 status within 5 seconds to acknowledge receipt
2. **Process Asynchronously**: Handle heavy processing in background jobs
3. **Store Raw Payloads**: Log raw webhook payloads for debugging
4. **Handle Retries**: Implement idempotency to handle duplicate webhooks
5. **Monitor Failures**: Set up alerts for failed webhook deliveries

## Testing Webhooks

Use our staging environment to test webhook integration:

```bash theme={null}
https://staging.api.mavapay.co/api/v1
```

Consider using tools like:

* [webhook.site](https://webhook.site) for inspecting payloads
* [ngrok](https://ngrok.com) for local development
* [RequestBin](https://requestbin.com) for testing

## Next Steps

* Learn how to [register webhooks](/api-reference/endpoint/webhook/register-webhook)
* Explore [quote examples](/api-reference/quote-examples) for different currencies
* View [beneficiary formats](/api-reference/beneficiary-formats) for payment details
