Core API

Webhooks

Receive real-time payment notifications. Configure endpoints, verify signatures, and handle events.

Overview

Webhooks let your server receive instant HTTP notifications when payments succeed, fail, or change status. No polling required.

Register a Webhook

bash
curl -X POST "https://paynexus.co.ke/api/webhooks/register" \
  -H "X-API-Key: sk_your_secret_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Payment Webhook",
    "url": "https://your-domain.com/webhook/mpesa",
    "events": ["payment.completed", "payment.failed"]
  }'

Webhook Payload

Successful Payment

json
{
  "event": "payment.completed",
  "timestamp": "2026-01-27T10:17:18+03:00",
  "data": {
    "payment_id": 123,
    "merchant_id": 456,
    "reference": "PNXABC123DEF",
    "amount": "100.00",
    "currency": "KES",
    "phone": "254746990866",
    "status": "completed",
    "account_reference": "ORDER_123",
    "checkout_request_id": "ws_CO_27012026101718139746990866",
    "transaction_id": "OEI2AK4Q16",
    "provider_transaction_id": "OEI2AK4Q16",
    "provider_reference": "Success",
    "payer_name": "M-Pesa 254746990866"
  }
}

Failed Payment

json
{
  "event": "payment.failed",
  "timestamp": "2026-01-27T10:17:18+03:00",
  "data": {
    "payment_id": 123,
    "reference": "PNXABC123DEF",
    "amount": "100.00",
    "status": "failed",
    "failure_reason": "Insufficient funds",
    "user_message": "The request was cancelled by the user",
    "retry_possible": false
  }
}

Signature Verification

All webhooks include an HMAC signature in the X-PayNexus-Signature header. Verify it to confirm authenticity:

php
function verifyWebhookSignature(string $payload, string $signature, string $secret): bool
{
    $expectedSignature = hash_hmac('sha256', $payload, $secret);
    return hash_equals($expectedSignature, $signature);
}

$signature = $_SERVER['HTTP_X_PAYNEXUS_SIGNATURE'] ?? '';
$payload = file_get_contents('php://input');

if (!verifyWebhookSignature($payload, $signature, $_ENV['PAYNEXUS_WEBHOOK_SECRET'])) {
    http_response_code(401);
    exit;
}

echo json_encode(['ResultCode' => 0, 'ResultDesc' => 'Received']);

Available Events

Event Description
payment.completedPayment successful
payment.failedPayment failed
payment.initiatedPayment initiated
invoice.createdInvoice created
invoice.paidInvoice paid
invoice.overdueInvoice overdue
subscription.createdSubscription created
subscription.canceledSubscription canceled

Best Practices

Return 200 quickly

Process webhooks asynchronously. Return a 200 response immediately to prevent retries.

Verify signatures

Always verify the X-PayNexus-Signature header before processing.

Handle duplicates

Webhooks may be delivered more than once. Use the reference or payment_id to deduplicate.