Skip to content
BirrPay

Webhooks

BirrPay POSTs a signed JSON payload to your app's webhook endpoint for every payment state change. Configure the endpoint in your app's Webhooks tab.

Envelope

{
  "event": "payment.succeeded",
  "created_at": "2026-08-29T09:00:00.000Z",
  "data": {
    "reference": "order_8xk29f",
    "amount": 15000,
    "currency": "NGN",
    "provider": "paystack",
    "customer": { "email": "payer@example.com" },
    "fees": { "fee": 325, "net": 14675 },
    "metadata": { "order_id": "8xk29f" }
  }
}

Events

  • checkout.session.created
  • payment.pending
  • payment.succeeded
  • payment.failed
  • payment.expired
  • test.event (sent by the "Send test event" button)

Verifying the signature

Header X-BirrPay-Signature looks like t=1756458000,v1=5257a869.... Compute HMAC-SHA256 over the string {t}.{rawBody} using your app's webhook secret and compare with v1 in constant time. Reject if older than 5 minutes.

import crypto from 'node:crypto';

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')));
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Reliability

BirrPay retries failed deliveries with exponential backoff up to 8 attempts, then marks the delivery dead. You can replay any delivery from the dashboard. Process events idempotently — duplicates can occur.

Ready to take your first payment?

Create account