Payments
Webhooks
Volboo POSTs an event to your server the moment something happens on your business, so you learn about a payment without polling for it.
Registering your URL
In the dashboard, open Business Setting → Webhook and set the URL that should receive completed payments. It is set per business, so each business can point at a different service. You will also find your Webhook Secret Key here.
- Serve it over HTTPS.
- Answer
200as soon as you have stored or queued the event. - Do the slow work afterwards, out of the request.
The event
A completed collection arrives as payment.success:
payment.success
{
"event": "payment.success",
"biz_id": "biz_69446ae056698",
"transaction_reference": "VOLC_6A7F33B650C15",
"bank_code": "9psb",
"amount": 500,
"net_amount": 496,
"acct_reference": "bill_vol-57A65454147E",
"acct_vol_reference": "VOL-6A46715085888-9PS",
"status": "completed",
"source": {
"account_name": "GRACE EBOHON",
"account_number": "8101543393",
"bank_name": "Palmpay"
},
"timestamp": "2026-08-14T16:26:46+01:00"
}
| Field | Notes |
|---|---|
| event | What happened. payment.success for a completed collection. |
| biz_id | The business the payment belongs to. |
| transaction_reference | Pass this to the transaction endpoint to verify. |
| bank_code | Bank code processing the transaction (e.g. 9psb). |
| amount | What the customer paid. |
| net_amount | What reached your balance, after fees. |
| acct_reference | The reference on the virtual account that was paid into. |
| acct_vol_reference | Volboo's identifier for that account. |
| status | State of the transaction. |
| source | Who paid: account name, number and bank. |
| timestamp | ISO 8601, with offset. |
Verifying webhook signatures
Volboo signs all webhook events by including an X-Webhook-Signature header with every request.
Before processing a payload, calculate an HMAC-SHA256 hash using your raw request payload and your Webhook Secret Key, then verify it matches the signature header.
Receiving and verifying an event, PHP
// 1. Read raw request payload & signature header $data = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? ''; $secret_key = 'YOUR_WEBHOOK_SECRET_KEY'; // 2. Compute HMAC SHA-256 hash $hashkey = hash_hmac('sha256', $data, $secret_key); // 3. Verify signature before processing if (!hash_equals($hashkey, $signature)) { http_response_code(401); exit('Invalid webhook signature'); } // 4. Signature valid: answer immediately http_response_code(200); $event = json_decode($data, true); // 5. Ignore repeats if (already_processed($event['transaction_reference'])) return; // 6. Confirm against the API before updating state $verified = volboo_get_transaction($event['transaction_reference']); if ($verified['status'] === 'success') { credit_customer($event['acct_reference'], $verified); }
Delivery
- Handle repeats. Store
transaction_referenceand make your handler safe to run twice on the same event. - Answer fast. Acknowledge first, reconcile after.
- Deliveries and their payloads are listed in the dashboard under Business Setting → Webhook, which is where to look when your endpoint was down.
Security tip: Always compute the HMAC hash against the raw request body string (
php://input) before parsing it as JSON. Use hash_equals() rather than direct comparison operators (==) to prevent timing attack vulnerabilities.
Volboo