Webhook
Receive asynchronous notifications when payments or transactions change status, and verify that incoming webhook calls are genuine.
Webhook delivery (status callback)
POST
https://your-domain.com/webhookFinvyPay sends a POST request to your webhook URL whenever a transaction status changes (for example, when a payment succeeds or fails).
The JSON below uses dummy data. In production, values such as
amount, order_id, txn_id, and webhookUrl will match your real transactions.Example request body
{
"request": {
"success": true,
"status": "SUCCESS",
"data": {
"amount": 470.55,
"currency": "USD",
"order_id": "ORD-EXAMPLE-01-card",
"txn_id": "FP2603EXAMPLE00025",
"firstName": "Christine",
"lastName": "Ankunding",
"address": "458 Toy Green Apt. 593",
"city": "East Kraigburgh",
"state": "RI",
"country": "US",
"email": "customer@example.com",
"webhookUrl": "https://your-domain.com/webhook"
}
}
}Example headers
Along with the JSON payload, FinvyPay includes headers that help you identify and verify the webhook call:
{
"x-webhook-attempt": ["3"],
"x-transaction-id": ["FP2603EXAMPLE00025"],
"x-forwarded-proto": ["https"],
"x-forwarded-host": ["your-domain.com"],
"x-forwarded-for": ["203.0.113.42"],
"sec-fetch-mode": ["cors"],
"fs-webhook-hash": ["8cb457be02471cefdf40549a87ee41b5e0916b9a30760e3b926418404e0cb7a8"],
"content-type": ["application/json"],
"accept-language": ["*"],
"accept-encoding": ["gzip, deflate, br"]
}The
fs-webhook-hash header contains an HMAC-SHA256 signature of the raw request body, created using your webhook secret. You must recompute this hash on your server and compare it with the value in the header to verify the webhook.Verifying the webhook signature (PHP example)
The example below shows how to verify the webhook signature using PHP. The same logic applies to any language that supports HMAC-SHA256.
<?php
// 1. Read the raw request body exactly as received
$rawBody = '{"success":true,"status":"SUCCESS","data":{"amount":1,"currency":"USD","order_id":"ORD-EXAMPLE-123","txn_id":"FP2603EXAMPLE00036","firstName":"John","lastName":"Doe","address":"123 Main Street","city":"New York","state":"NY","country":"US","email":"john@example.com","webhookUrl":"https://your-domain.com/webhook"}}';
// 2. Your webhook secret from the FinvyPay Dashboard (Settings → Config)
$webhookSecret = 'YOUR_WEBHOOK_SECRET_HERE';
// 3. Hash received from the fs-webhook-hash header (no whitespace or newlines)
// Example: $receivedHash = $_SERVER['HTTP_FS_WEBHOOK_HASH'] ?? '';
$receivedHash = 'RECEIVED_HASH_FROM_HEADER';
// 4. Generate expected hash using HMAC-SHA256
$expectedHash = hash_hmac('sha256', $rawBody, $webhookSecret);
// 5. Validate signature using timing-safe comparison
if (hash_equals($expectedHash, $receivedHash)) {
http_response_code(200);
echo "VALID\n";
// Process the webhook (update order status, etc.)
} else {
http_response_code(400);
echo "INVALID\n";
}
- Always use the exact raw request body when computing the HMAC (before any JSON reformatting).
- Use a secure comparison function such as
hash_equalsto avoid timing attacks. - Store your webhook secret securely and never expose it in client-side code.