Live Pay

LivePay

Webhook API

Real-time transaction status notifications

Overview

Webhooks allow you to receive real-time notifications when a transaction status changes. When a transaction is completed (success or failure), we will send an HTTP POST request to your configured webhook URL.

Important

Your webhook endpoint must return a 200 OK response within 10 seconds. Failed deliveries will be retried up to 3 times with a 30-second delay between attempts.

Webhook Payload

webhook-payload.json
{
  "status": "Success",
  "message": "Payment completed successfully",
  "customer_reference": "INV-123456789",
  "internal_reference": "550e8400-e29b-41d4-a716-446655440000",
  "provider_transaction_id": "987654321",
  "msisdn": "+256777123456",
  "amount": 50000,
  "currency": "UGX",
  "provider": "MTN",
  "charge": 1500,
  "completed_at": "2024-01-15 10:35:00"
}

Signature Verification

Each webhook request includes a X-Webhook-Signature header.

Header
X-Webhook-Signature: t=1705314900,v=5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Signature Generation

The signature is generated using HMAC-SHA256 with your webhook secret key:

Signature String Format
string = webhook_url + timestamp + sorted_params

sorted_params = status, customer_reference, internal_reference sorted alphabetically by key, with each key and value joined together directly
Example
webhook_url: https://your-domain.com/webhook
timestamp: 1781882665
status: Success
customer_reference: INV-123
internal_reference: abc-456

Sorted params (alphabetical): customer_reference, internal_reference, status

Final string:
https://your-domain.com/webhook1781882665customer_referenceINV-123internal_referenceabc-456statusSuccess

Verification Example

verify.js
const crypto = require('crypto');

function verifyWebhookSignature(payload, signatureHeader, webhookUrl, secret) {
    const [timestampPart, signaturePart] = signatureHeader.split(',');
    const timestamp = timestampPart.split('=')[1];
    const receivedSignature = signaturePart.split('=')[1];
    
    const params = {
        status: payload.status,
        customer_reference: payload.customer_reference,
        internal_reference: payload.internal_reference
    };
    
    const sortedKeys = Object.keys(params).sort();
    let stringToSign = webhookUrl + timestamp;
    for (const key of sortedKeys) {
        stringToSign += key + params[key];
    }
    
    const expectedSignature = crypto
        .createHmac('sha256', secret)
        .update(stringToSign)
        .digest('hex');
    
    return receivedSignature === expectedSignature;
}