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 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.
{
"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.
{
"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 |
On-chain withdrawals remain in PENDING status until there are 3 block confirmations, after which the status changes to SUCCESS.
Payment Link Webhooks
payment_link.settled
Triggered when a Payment Link transaction is fully settled (after block confirmations for on-chain).
{
"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.
{
"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 |
NGN amounts are in kobo. Divide by 100 to get the amount in Naira.
South African Rand (ZAR) Webhooks
payment.sent (Withdrawal)
Triggered when ZAR payment is sent to a beneficiary.
{
"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 |
ZAR amounts are in cents. Divide by 100 to get the amount in Rand.
Kenyan Shilling (KES) Webhooks
payment.sent (Withdrawal)
Triggered when KES payment is sent via M-Pesa.
{
"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"
},
"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 | M-Pesa payment type (paytophone, paytobill, paytotill) |
kesTransactionMetadata.identifiers | M-Pesa payment details (varies by type) |
KES amounts are in cents. Divide by 100 to get the amount in Shillings.
Ghanaian Cedi (GHS) Webhooks
payment.sent (Withdrawal)
Triggered when GHS payment is sent via MTN Mobile Money.
{
"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 |
GHS amounts are in pesewa. Divide by 100 to get the amount in Cedis.
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:
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
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:
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
- Respond Quickly: Return a 200 status within 5 seconds to acknowledge receipt
- Process Asynchronously: Handle heavy processing in background jobs
- Store Raw Payloads: Log raw webhook payloads for debugging
- Handle Retries: Implement idempotency to handle duplicate webhooks
- Monitor Failures: Set up alerts for failed webhook deliveries
Testing Webhooks
Use our staging environment to test webhook integration:
https://staging.api.mavapay.co/api/v1
Consider using tools like:
Next Steps