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.createdpayment.pendingpayment.succeededpayment.failedpayment.expiredtest.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