Webhooks
Receive real-time notifications about payment events with secure, reliable webhook delivery and automatic retries.
Events Overview
VeriPay sends webhook events to notify your application when important events happen in your account. Webhooks are particularly useful for events that are not triggered by direct API requests.
Payment Events
- • payment.validated
- • payment.rejected
- • payment.proof_uploaded
- • payment_link.created
Invoice Events
- • invoice.paid
- • invoice.overdue
- • invoice.viewed
- • invoice.sent
Security & Verification
VeriPay signs all webhook payloads with HMAC-SHA256 using your webhook signing secret. Always verify the signature before processing webhook data.
Signature Verification
<?php
// Get the signature from headers
$signature = $_SERVER['HTTP_X_VERIPAY_SIGNATURE'];
$payload = file_get_contents('php://input');
// Parse the signature header
list($timestamp, $signature_hash) = explode(',', $signature);
$timestamp = str_replace('t=', '', $timestamp);
$signature_hash = str_replace('v1=', '', $signature_hash);
// Verify timestamp (prevent replay attacks)
if (abs(time() - (int)$timestamp) > 300) { // 5 minutes
http_response_code(400);
exit('Request too old');
}
// Compute expected signature
$expected_signature = hash_hmac(
'sha256',
$timestamp . '.' . $payload,
$webhook_secret
);
// Verify signature (constant time)
if (!hash_equals($expected_signature, $signature_hash)) {
http_response_code(401);
exit('Invalid signature');
}
// Process the webhook
$event = json_decode($payload, true);
processWebhook($event);
Security Best Practices
Payload Format
All webhook events follow a consistent JSON structure:
{
"id": "evt_1234567890abcdef",
"type": "payment.validated",
"occurred_at": "2024-08-14T10:30:00Z",
"data": {
"payment_link": {
"id": "ABC123XY",
"status": "verified",
"amount": 150.00,
"currency": "TTD",
"reference": "ORDER-12345",
"source_reference": "order_12345"
}
},
"meta": {
"attempt": 1
}
}
Retries & Backoff
VeriPay automatically retries failed webhook deliveries with exponential backoff:
Attempt | Delay | Total Time |
---|---|---|
1 | 30 seconds | 30s |
2 | 2 minutes | 2m 30s |
3 | 10 minutes | 12m 30s |
4 | 30 minutes | 42m 30s |
5 | 2 hours | 2h 42m 30s |
6 | 6 hours | 8h 42m 30s |
Response Requirements
Sample Webhook Endpoint
<?php
// routes/web.php
Route::post('/webhooks/veripay', [WebhookController::class, 'handle']);
// app/Http/Controllers/WebhookController.php
class WebhookController extends Controller
{
public function handle(Request $request)
{
// Verify the signature (see security section)
$this->verifySignature($request);
$event = $request->all();
switch ($event['type'] ?? null) {
case 'payment.validated':
$this->handlePaymentValidated($event['data']);
break;
case 'payment.rejected':
$this->handlePaymentRejected($event['data']);
break;
case 'invoice.paid':
$this->handleInvoicePaid($event['data']);
break;
default:
Log::info('Unhandled webhook event: ' . ($event['type'] ?? 'unknown'));
}
return response()->json(['status' => 'success']);
}
private function handlePaymentValidated(array $data): void
{
$paymentLink = $data['payment_link'];
// Update your local order status
Order::where('veripay_invoice_id', $paymentLink['id'])
->update(['status' => 'paid']);
// Optional: Send confirmation email, etc.
}
}
Webhook Configuration
Configure your webhook endpoints in the VeriPay dashboard:
- Navigate to Settings → Webhooks in your dashboard
- Add your webhook endpoint URL
- Select the events you want to receive
- Copy your webhook signing secret
- Test the endpoint with a sample event
Next Steps
Now that you understand webhooks, implement them in your application: