Webhooks
Receive real-time notifications about payment events
Webhooks
Webhooks allow your application to receive real-time notifications when events happen in your ZEUSXPAY account. This is the recommended way to handle payment confirmations.
Why Use Webhooks?
- Real-time updates: Get notified immediately when events occur
- Reliable: We retry failed deliveries automatically
- Secure: Cryptographically signed for verification
- Asynchronous: Don’t depend on customers returning to your site
Setting Up Webhooks
1. Create an Endpoint
Create an endpoint on your server to receive webhook events:
const express = require('express');
const app = express();
app.post('/webhooks/zeusxpay', express.raw({ type: 'application/json' }), (req, res) => {
const event = JSON.parse(req.body);
// Handle the event
console.log('Received event:', event.type);
// Return 200 to acknowledge receipt
res.status(200).send('OK');
}); 2. Register Your Webhook URL
Register your endpoint in the Dashboard:
- Go to Settings → Webhooks
- Click Add Endpoint
- Enter your URL:
https://yoursite.com/webhooks/zeusxpay - Select events to receive
- Save and copy your webhook secret
Event Types
Order Events
order.created- Order was createdorder.confirming- Payment detected, waiting for confirmationsorder.completed- Payment confirmed and completedorder.expired- Order expired without paymentorder.failed- Payment failed
Refund Events
refund.created- Refund initiatedrefund.completed- Refund completedrefund.failed- Refund failed
Example Event Payload
{
"id": "evt_1234567890",
"type": "order.completed",
"created_at": "2024-01-01T12:00:00Z",
"data": {
"id": "ord_1234567890",
"status": "completed",
"amount": 100.0,
"currency": "USD",
"crypto_currency": "BTC",
"crypto_amount": 0.00234567,
"transaction_hash": "abc123...",
"customer_email": "customer@example.com",
"metadata": {
"order_id": "12345"
}
}
} Verifying Webhook Signatures
Always verify webhook signatures to ensure requests are from ZEUSXPAY:
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expectedSignature = crypto.createHmac('sha256', secret).update(payload).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
}
app.post('/webhooks/zeusxpay', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-zeusxpay-signature'];
const payload = req.body.toString();
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
// Handle event...
res.status(200).send('OK');
}); Handling Events
Process different event types:
app.post('/webhooks/zeusxpay', async (req, res) => {
const event = JSON.parse(req.body);
try {
switch (event.type) {
case 'order.created':
await handleOrderCreated(event.data);
break;
case 'order.confirming':
await handleOrderConfirming(event.data);
break;
case 'order.completed':
await handleOrderCompleted(event.data);
break;
case 'order.failed':
await handleOrderFailed(event.data);
break;
case 'refund.completed':
await handleRefundCompleted(event.data);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
res.status(200).send('OK');
} catch (error) {
console.error('Webhook error:', error);
res.status(500).send('Error processing webhook');
}
});
async function handleOrderCompleted(order) {
// Fulfill the order
console.log(`Order ${order.id} completed`);
// Update database
await db.orders.update({
where: { id: order.metadata.order_id },
data: { status: 'paid', payment_id: order.id }
});
// Send confirmation email
await sendEmail(order.customer_email, {
subject: 'Payment Received',
template: 'payment-confirmation',
data: order
});
} Best Practices
1. Return 200 Quickly
Return a 200 status immediately and process asynchronously:
app.post('/webhooks/zeusxpay', async (req, res) => {
const event = JSON.parse(req.body);
// Acknowledge receipt immediately
res.status(200).send('OK');
// Process asynchronously
processWebhookAsync(event).catch(console.error);
}); 2. Idempotency
Handle duplicate events gracefully:
async function handleOrderCompleted(order) {
// Check if already processed
const existing = await db.payments.findUnique({
where: { zeusxpay_order_id: order.id }
});
if (existing) {
console.log('Event already processed');
return;
}
// Process the payment
await fulfillOrder(order);
} 3. Error Handling
Handle errors properly to trigger retries:
app.post('/webhooks/zeusxpay', async (req, res) => {
try {
const event = JSON.parse(req.body);
await processEvent(event);
res.status(200).send('OK');
} catch (error) {
console.error('Webhook processing failed:', error);
// Return 500 to trigger retry
res.status(500).send('Processing failed');
}
}); 4. Logging
Log all webhook events for debugging:
app.post('/webhooks/zeusxpay', async (req, res) => {
const event = JSON.parse(req.body);
// Log to database
await db.webhookLogs.create({
data: {
event_id: event.id,
event_type: event.type,
payload: event,
processed_at: new Date()
}
});
// Process event...
}); Retry Logic
ZEUSXPAY automatically retries failed webhook deliveries:
- Immediate retry: If first attempt fails
- Exponential backoff: 1min, 5min, 30min, 2hr, 6hr, 12hr, 24hr
- Maximum attempts: 10 attempts over 3 days
- Manual retry: Retry failed webhooks from Dashboard
Testing Webhooks
Local Development
Use tools like ngrok to expose your local server:
# Start ngrok
ngrok http 3000
# Use the ngrok URL in your webhook settings
https://abc123.ngrok.io/webhooks/zeusxpay Test Events
Send test webhooks from the Dashboard:
- Go to Settings → Webhooks
- Select your endpoint
- Click Send Test Event
- Choose event type
- View response
CLI Testing
Use cURL to simulate webhooks:
curl -X POST http://localhost:3000/webhooks/zeusxpay
-H "Content-Type: application/json"
-H "X-ZeusXPay-Signature: test_signature"
-d '{
"id": "evt_test_123",
"type": "order.completed",
"data": {
"id": "ord_test_123",
"status": "completed"
}
}' Monitoring
Monitor webhook delivery in the Dashboard:
- Success rate: View delivery success rate
- Recent deliveries: See recent webhook attempts
- Failed deliveries: Review and retry failed webhooks
- Logs: View full request/response logs
Security Considerations
- ✅ Always verify signatures
- ✅ Use HTTPS endpoints only
- ✅ Validate event data
- ✅ Implement idempotency
- ✅ Rate limit your endpoint
- ❌ Don’t trust unverified webhooks
- ❌ Don’t process duplicate events
- ❌ Don’t expose sensitive data in logs
Troubleshooting
Webhooks Not Received
- Check your firewall allows incoming requests
- Verify webhook URL is publicly accessible
- Check Dashboard for delivery logs
- Ensure endpoint returns 200 status
Signature Verification Fails
- Use raw request body (don’t parse before verifying)
- Check you’re using the correct webhook secret
- Verify signature header name:
x-zeusxpay-signature
Duplicate Events
- Implement idempotency checks
- Store processed event IDs
- Check timestamp to detect replays
Examples
See our GitHub repository for complete webhook examples in multiple languages:
- Node.js/Express
- Python/Flask
- PHP/Laravel
- Ruby/Rails
- Go
Need Help?
- Check the API Reference
- Review Authentication Guide
- Join our Discord
- Email support@zeusxpay.io
