Receive real-time notifications about payment events to keep your systems in sync.
ZenPay webhooks provide a way for your application to receive real-time notifications when payment events occur. Instead of polling our API for updates, webhooks push notifications to your server whenever events happen, enabling you to automatically respond to payment status changes, refunds, disputes, and more.
Get instant notifications about payment events.
Enhanced security for your webhook endpoints.
Easy integration with any backend system.
Ensures all events reach your application.
Follow these steps to configure webhooks for your ZenPay account:
First, create an endpoint on your server that can receive POST requests from ZenPay:
Add your webhook endpoint to your ZenPay account:
Implement signature verification in your endpoint code:
Process the webhook payload and update your systems accordingly:
ZenPay webhooks support the following event types:
| Event Type | Description | When It's Triggered |
|---|---|---|
| payment.created | A new payment has been created | When a customer initiates a payment |
| payment.pending | Payment is awaiting confirmation | When payment is detected but not yet confirmed |
| payment.completed | Payment has been completed successfully | When payment receives required confirmations |
| payment.failed | Payment attempt has failed | When payment expires or is rejected |
| payment.refunded | Payment has been refunded | When a refund is processed |
| checkout.completed | Checkout process completed | When customer completes the checkout flow |
| checkout.abandoned | Checkout was started but not completed | When checkout expires without payment |
| subscription.created | New subscription has been created | When a customer subscribes to a plan |
| subscription.updated | Subscription details have changed | When subscription plan or status changes |
| subscription.canceled | Subscription has been canceled | When a subscription is terminated |
Each webhook notification contains a JSON payload with information about the event:
{
"id": "evt_5f7e243e8b9c4",
"type": "payment.completed",
"created": 1626285966,
"data": {
"object": {
"id": "pay_6g8h354f9c0d5",
"amount": "99.99",
"currency": "USD",
"crypto_amount": "0.00312",
"crypto_currency": "BTC",
"status": "completed",
"customer": {
"email": "customer@example.com",
"name": "John Doe"
},
"metadata": {
"order_id": "ORD-12345",
"product_id": "PRD-6789"
},
"created": 1626285900,
"updated": 1626285966,
"transaction_hash": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"confirmation_count": 6,
"checkout_session_id": "cs_7h9i465g0d1e6"
}
}
}To ensure webhooks are coming from ZenPay and haven't been tampered with, you should verify the signature:
// Using the ZenPay Node.js SDK
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const app = express();
// Use raw body parser for webhook signature verification
app.use('/webhooks/zenpay',
bodyParser.raw({ type: 'application/json' }),
(req, res) => {
const payload = req.body;
const signature = req.headers['zenpay-signature'];
const webhookSecret = 'whsec_your_webhook_secret';
// Verify signature
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(payload)
.digest('hex');
// Check if signatures match
if (signature !== expectedSignature) {
console.error('Invalid signature');
return res.status(400).send('Invalid signature');
}
// Parse the payload
const event = JSON.parse(payload);
// Handle different event types
switch (event.type) {
case 'payment.completed':
// Update order status, send confirmation email, etc.
const paymentId = event.data.object.id;
const amount = event.data.object.amount;
const currency = event.data.object.currency;
console.log(`Payment ${paymentId} completed: ${amount} ${currency}`);
break;
case 'payment.failed':
// Handle failed payment
console.log(`Payment ${event.data.object.id} failed`);
break;
// Handle other event types
default:
console.log(`Unhandled event type: ${event.type}`);
}
// Return a response to acknowledge receipt of the webhook
res.status(200).send('Webhook received');
}
);
app.listen(3000, () => console.log('Webhook server running on port 3000'));