๐ Introduction: What are Webhooks?
Webhooks are HTTP callbacks that a payment gateway sends to your server to notify you about payment events. They are the essential mechanism for automating order fulfillment, updating order statuses, and integrating payment confirmations into your application workflow.
Unlike polling (repeatedly calling the API to check status), webhooks provide real-time notifications and reduce API load. When a payment is confirmed, expired, or refunded, the gateway instantly sends a structured payload to your configured webhook URL.
Webhooks are push-based โ the gateway sends data to you. Polling is pull-based โ you repeatedly request data. Webhooks are more efficient, faster, and reduce server load.
๐ Step-by-Step Setup Guide
Step 1: Create Your Webhook Endpoint
Create an endpoint on your server that accepts POST requests. This is the URL where the gateway will send webhook notifications.
- URL format โ
https://yoursite.com/api/webhooks/payment - Method โ POST
- Content-Type โ application/json (typically)
- Response โ return HTTP 200 OK (2xx) to acknowledge receipt
Step 2: Configure Webhook in Gateway Dashboard
Log in to your payment gateway dashboard and navigate to the webhook configuration section:
- Endpoint URL โ paste your server endpoint URL
- Event Selection โ choose which events to subscribe to:
| Event | Description | Action |
|---|---|---|
payment.created | Payment request created | Log transaction |
payment.received | Transaction detected on blockchain | Update order status (pending) |
payment.confirmed | Sufficient confirmations reached | Fulfill order (ship, grant access) |
payment.expired | Payment request expired | Cancel order, notify customer |
payment.underpaid | Amount received is less than expected | Notify customer, request additional |
payment.overpaid | Amount received is more than expected | Manual review or automatic refund |
refund.completed | Refund processed | Update order status |
Step 3: Implement Signature Verification
To prevent forged webhook requests, most gateways sign webhook payloads with a secret key. Here's how to verify:
// Node.js example: Verify webhook signature
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
const payload = req.body;
const signature = req.headers['x-webhook-signature'];
const isValid = verifyWebhook(payload, signature, WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
Step 4: Handle Events
Process the webhook payload based on the event type:
// Example webhook handler
app.post('/webhooks/payment', (req, res) => {
const event = req.body;
switch (event.type) {
case 'payment.confirmed':
// Fulfill the order
const orderId = event.data.order_id;
updateOrderStatus(orderId, 'paid');
sendConfirmationEmail(orderId);
break;
case 'payment.expired':
// Cancel the order
cancelOrder(event.data.order_id);
break;
case 'refund.completed':
// Update refund status
updateRefundStatus(event.data.refund_id, 'completed');
break;
default:
// Log unknown event type
console.log('Unhandled event:', event.type);
}
res.status(200).send('OK');
});
Step 5: Test in Sandbox Environment
Before going live, test your webhook implementation in the gateway's sandbox environment:
- Simulate events โ most gateways allow you to manually trigger webhook events from the dashboard.
- Check responses โ verify that your endpoint returns 2xx status codes.
- Monitor logs โ check your server logs to confirm payload receipt and processing.
- Test failure scenarios โ simulate endpoint failure to verify gateway retry behavior.
๐ก๏ธ Webhook Security Best Practices
Implement these security measures to protect your webhook endpoint:
Always verify the webhook signature using the gateway's secret key. This ensures the request is genuinely from the gateway.
Handle duplicate webhook notifications safely. Store a transaction ID and skip processing if already handled.
Always use HTTPS for webhook endpoints. Never accept insecure HTTP connections.
If possible, whitelist the gateway's IP address range to prevent unauthorized requests.
๐ Common Webhook Events
| Event | Payload Example | Recommended Action |
|---|---|---|
payment.confirmed |
{ "type": "payment.confirmed", "data": { "payment_id": "pay_123", "order_id": "ord_456", "amount": "100.00", "currency": "USD" } } |
Fulfill the order, send confirmation |
payment.expired |
{ "type": "payment.expired", "data": { "payment_id": "pay_123", "order_id": "ord_456" } } |
Cancel the order, notify customer |
payment.underpaid |
{ "type": "payment.underpaid", "data": { "payment_id": "pay_123", "expected": "100.00", "received": "50.00" } } |
Notify customer, request additional payment |
refund.completed |
{ "type": "refund.completed", "data": { "refund_id": "ref_123", "payment_id": "pay_456", "amount": "100.00" } } |
Update refund status in your system |
๐ง Troubleshooting Webhooks
Common issues and how to resolve them:
| Issue | Possible Cause | Solution |
|---|---|---|
| Webhook not received | Incorrect endpoint URL, firewall blocking, server down | Check URL, whitelist IPs, check server status |
| Signature verification fails | Incorrect secret key, payload format mismatch | Verify secret key, use raw payload (not parsed JSON) |
| Duplicate webhooks | Gateway retry mechanism, network issues | Implement idempotency (store processed IDs) |
| Slow response times | Heavy processing in endpoint | Process asynchronously (queue job), respond quickly |
| SSL certificate errors | Expired or invalid certificate | Renew/update SSL certificate |