Webhook Integration
Learn how to set up webhooks to receive real-time notifications about payment events and transaction updates.
What are Webhooks?
Webhooks are HTTP callbacks that notify your application when specific events occur in your Gafiapay account. Instead of polling our API for updates, webhooks push data to your server in real-time.
Supported Events
| Event | Description | Triggered When |
|---|---|---|
payment.success | Payment completed successfully | A payment is confirmed and processed |
payment.failed | Payment failed | A payment attempt fails |
account.created | Virtual account created | A new virtual account is generated |
Setting Up Webhooks
Step-by-Step Setup
Create Webhook Endpoint
Create a public HTTPS endpoint on your server to receive webhook notifications.
Configure in Dashboard
Go to Settings → Webhook Settings in the Gafiapay dashboard and add your webhook URL to update your webhook configuration.
Webhook Payload Structure
All webhook payloads follow a consistent structure:
{
"data": {
"transaction": {
"id": "68a990e4917e8283a1351fc6",
"orderNo": "MI1959193613179124912",
"email": "user@domain.com",
"amount": 1000,
"currency": "NGN",
"status": "completed",
"charges": {
"amount": 0.1,
"type": "payment",
"percentage": 1
},
"metadata": {
"payerAccountName": "John Doe",
"payerAccountNo": "9023456789",
"payerBankName": "PALMPAY",
"virtualAccountNo": "669634239",
"createdTime": "2025-08-23T09:58:52.096Z",
"updateTime": "2025-08-23T09:58:52.096Z",
"grossAmount": 10,
"netAmount": 9.9,
"chargeAmount": 0.1,
"chargePercentage": 1,
"chargeType": "percentage"
},
"description": "incoming payment of NGN1000 from Johndoe (PALMPAY)"
}
}
} Webhook Security
🔐 IP Whitelist
Webhooks are only accepted from whitelisted IP addresses for security.
✅ Signature Verification
Each webhook includes a signature header that must be verified using HMAC SHA256.
⏱️ Timestamp Validation
Webhooks include a timestamp header for additional security validation.
Implementation Examples
Code Examples
Select your preferred programming language to view the implementation
JavaScript Example
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.GAFIAPAY_SECRET_KEY;
const ALLOWED_IPS = ['38.242.149.154'];
app.post('/webhook', (req, res) => {
const signature = req.headers['x-signature'];
const ip_address = req.headers['x-forwarded-for'] || req.ip;
const timestamp = req.headers['x-timestamp'];
const payload = req.body;
// Validate IP address
if (!ALLOWED_IPS.includes(ip_address)) {
console.log('Invalid IP address:', ip_address);
return res.status(403).send('Permission denied, invalid IP address');
}
// Verify signature
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(timestamp)
.digest('hex');
if (signature !== expectedSignature) {
return res.status(403).send('Invalid signature');
}
// Process webhook
const { data } = payload;
const { transaction } = data;
console.log('Payment received:', {
id: transaction.id,
orderNo: transaction.orderNo,
email: transaction.email,
amount: transaction.amount,
currency: transaction.currency,
status: transaction.status,
charges: transaction.charges,
metadata: transaction.metadata,
description: transaction.description
});
// Update user balance and create transaction record
// Your business logic here
res.status(200).send('Transaction received successfully');
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
}); Required Headers
Your webhook endpoint must validate these headers:
| Header | Description | Example |
|---|---|---|
x-signature | HMAC SHA256 signature for verification | abc123... |
x-timestamp | Timestamp used in signature generation | 1647768600 |
x-forwarded-for | Client IP address for validation | 38.242.149.154 |
Testing Webhooks
You can test your webhook endpoint using tools like ngrok:
# Using ngrok to expose local server
ngrok http 3000
# Your webhook URL will be something like:
# https://abc123.ngrok.io/webhook Troubleshooting
Webhook Not Received
- Verify your webhook URL is publicly accessible
- Check that your server is running and responding
- Ensure your webhook endpoint accepts POST requests
- Check your server logs for any errors
Signature Verification Failed
- Verify you're using the correct webhook secret
- Ensure you're reading the raw request body
- Check that your signature generation matches our algorithm
IP Validation Failed
- Ensure your server can receive the correct IP address
- Check if you're behind a proxy or load balancer
- Verify the IP address matches our whitelist