Webhooks Overview
Webhooks allow you to receive real-time notifications when events happen in your Rach Payments account.
What are Webhooks?
Instead of continuously polling our API to check payment status, webhooks push notifications to your server instantly when important events occur.
Benefits:
- ⚡ Real-time notifications
- 🔄 Automatic retry logic
- 🔒 HMAC signature verification
- 📊 Delivery tracking
How Webhooks Work
Webhook Events
Payment Events
| Event | Description |
|---|---|
payment.confirmed | Payment received and confirmed on blockchain |
payment.expired | Checkout session expired without payment |
wallet.deposit.detected | Deposit detected on monitored wallet address |
Future Events
| Event | Description |
|---|---|
remittance.completed | Cross-border transfer completed |
remittance.failed | Transfer failed |
kyc.approved | KYC submission approved |
kyc.rejected | KYC submission rejected |
Webhook Payload Example
payment.confirmed
{
"event": "payment.confirmed",
"session_id": "chk_sess_abc123def456",
"reference": "ORDER-12345",
"amount": 100.00,
"currency": "USDT",
"status": "paid",
"payment_method": "crypto",
"network": "BSC",
"tx_hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"paid_at": "2025-12-22T10:30:45Z",
"created_at": "2025-12-22T10:00:00Z",
"metadata": {
"user_id": "usr_123",
"plan": "premium"
},
"timestamp": 1703242245
}Setting Up Webhooks
1. Create a Webhook Endpoint
Create an HTTPS endpoint on your server to receive webhooks:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
app.post('/webhooks/payment', (req, res) => {
// 1. Verify signature
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature)) {
return res.status(401).send('Invalid signature');
}
// 2. Process webhook
const { event, session_id, status, reference } = req.body;
if (event === 'payment.confirmed' && status === 'paid') {
// Update your database
updateOrder(reference, 'paid');
// Fulfill order
fulfillOrder(reference);
}
// 3. Return 200 OK quickly
res.status(200).send('Webhook received');
});
function verifySignature(payload, signature) {
const secret = process.env.WEBHOOK_SECRET;
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
const expectedSignature = hmac.digest('hex');
return signature === expectedSignature;
}from flask import Flask, request, jsonify
import hmac
import hashlib
import json
import os
app = Flask(__name__)
@app.route('/webhooks/payment', methods=['POST'])
def webhook():
# 1. Verify signature
signature = request.headers.get('X-Webhook-Signature')
payload = request.get_json()
if not verify_signature(payload, signature):
return jsonify({'error': 'Invalid signature'}), 401
# 2. Process webhook
event = payload.get('event')
session_id = payload.get('session_id')
status = payload.get('status')
reference = payload.get('reference')
if event == 'payment.confirmed' and status == 'paid':
# Update database
update_order(reference, 'paid')
# Fulfill order
fulfill_order(reference)
# 3. Return 200 OK
return jsonify({'success': True}), 200
def verify_signature(payload, signature):
secret = os.getenv('WEBHOOK_SECRET')
expected_signature = hmac.new(
secret.encode(),
json.dumps(payload).encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)2. Configure Webhook URL
Set your webhook URL when creating a checkout:
{
"amount": 100.00,
"currency": "USDT",
"network": "BSC",
"customer_email": "customer@example.com",
"reference": "ORDER-12345",
"callback_url": "https://yoursite.com/webhooks/payment" // ← Your webhook URL
}Security: HMAC Signature Verification
Every webhook includes an X-Webhook-Signature header containing an HMAC-SHA256 signature.
How to Verify:
- Get the signature from
X-Webhook-Signatureheader - Compute HMAC-SHA256 of the raw request body using your webhook secret
- Compare the computed signature with the received signature
Always Verify Signatures
Never process webhooks without signature verification! This prevents unauthorized requests from triggering actions in your system.
Get Your Webhook Secret
Your webhook secret is available in your dashboard under Settings → Webhooks.
Retry Logic
If your endpoint returns an error or times out, we'll retry the webhook delivery:
Retry Schedule:
- Attempt 1: Immediate
- Attempt 2: After 30 seconds
- Attempt 3: After 60 seconds (2^1 × 30s)
- Attempt 4: After 120 seconds (2^2 × 30s)
- Attempt 5: After 240 seconds (2^3 × 30s)
Max Retries: 5 attempts over ~8 minutes
Best Practices
- Return
200 OKas quickly as possible - Process webhooks asynchronously (use a queue)
- Make your endpoint idempotent (handle duplicate webhooks)
Testing Webhooks
Local Development
Use tools like ngrok or localtunnel to expose your local server:
# Install ngrok
npm install -g ngrok
# Expose local port
ngrok http 3000
# Use the ngrok URL as your callback_url
# https://abc123.ngrok.io/webhooks/paymentManual Testing
Trigger test webhooks from your dashboard or use our API.
Troubleshooting
Webhook Not Received
- Check your endpoint is publicly accessible (HTTPS required)
- Verify no firewall blocking our IP range
- Check webhook delivery logs in dashboard
Signature Verification Failing
- Ensure you're using the correct webhook secret
- Verify you're computing HMAC on the raw request body
- Don't parse/modify the JSON before verification
Timeouts
- Return
200 OKwithin 10 seconds - Process work asynchronously
- Use a message queue for heavy processing
