Receive real-time notifications about your transaction status
Webhooks allow LivePay to send real-time transaction status updates to your application. Instead of polling our API for transaction status, you can set up a webhook endpoint to receive notifications when transactions are completed, failed, or have other status changes.
When a transaction status changes, LivePay sends an HTTP POST request to your configured webhook URL with the transaction details. Your server should process this information and return a 200 OK response.
{
"status": "Approved",
"message": "Request payment completed successfully.",
"type": "deposit",
"transaction_id": "tezd54ebc5f09d09",
"reference_id": "d54ebc5f09d09dd10a4c5d6b4595101",
"description": "Deposit #123456",
"phone": "256701234567",
"amount": "500.0",
"payment_method": "mtn",
"charge_amount": "15.5"
}
Content-Type: application/json livepay-signature: t=1696516200,v=a1b2c3d4e5f6...
All webhook requests include a signature for security verification. You must verify this signature to ensure the request is from LivePay and prevent malicious attacks.
t=TIMESTAMP,v=SIGNATURE
application/json
Your LivePay secret key
| Parameter | Type | Description |
|---|---|---|
status
|
String | Transaction status (Approved, Failed, Pending) |
transaction_id
|
String | LivePay transaction ID |
reference_id
|
String | Your original reference ID |
phone
|
String | Recipient's phone number |
amount
|
String | Transaction amount |
payment_method
|
String | airtel/mtn |
charge_amount
|
String | Transaction fee charged |
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "received",
"message": "Webhook processed successfully"
}
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": "Invalid signature"
}
const crypto = require('crypto'); // Express.js webhook handler app.post('/api/webhooks/livepay', (req, res) => { const secretKey = 'your-secret-key'; const signature = req.headers['livepay-signature']; const payload = JSON.stringify(req.body); // Parse signature const match = signature.match(/t=([0-9]+),v=([a-f0-9]{64})/); if (!match) { return res.status(400).json({ error: 'Invalid signature format' }); } const receivedTimestamp = match[1]; const receivedSignature = match[2]; // Verify timestamp (5-minute window) if (Math.abs(Date.now() / 1000 - parseInt(receivedTimestamp)) > 300) { return res.status(400).json({ error: 'Invalid timestamp' }); } // Generate signature for verification function generateSignature(secretKey, timestamp, params) { let signedData = timestamp; Object.keys(params).sort().forEach(key => { signedData += String(key) + String(params[key]); }); return crypto.createHmac('sha256', secretKey) .update(signedData) .digest('hex'); } const generatedSignature = generateSignature(secretKey, receivedTimestamp, req.body); if (generatedSignature !== receivedSignature) { return res.status(401).json({ error: 'Invalid signature' }); } // Process the webhook console.log('Webhook received:', req.body); // Return success response res.status(200).json({ status: 'received', message: 'Webhook processed successfully' }); });
Never process webhook requests without verifying the signature. This prevents malicious actors from sending fake events to your application.
Verify the timestamp to prevent replay attacks. Reject requests with timestamps more than 5 minutes old or in the future.
Webhooks may be delivered multiple times. Implement idempotency by checking if you've already processed a transaction with the same ID.