Skip to content

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

EventDescription
payment.confirmedPayment received and confirmed on blockchain
payment.expiredCheckout session expired without payment
wallet.deposit.detectedDeposit detected on monitored wallet address

Future Events

EventDescription
remittance.completedCross-border transfer completed
remittance.failedTransfer failed
kyc.approvedKYC submission approved
kyc.rejectedKYC submission rejected

Webhook Payload Example

payment.confirmed

json
{
  "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:

javascript
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;
}
python
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:

javascript
{
  "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:

  1. Get the signature from X-Webhook-Signature header
  2. Compute HMAC-SHA256 of the raw request body using your webhook secret
  3. 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 OK as 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:

bash
# 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/payment

Manual Testing

Trigger test webhooks from your dashboard or use our API.


Troubleshooting

Webhook Not Received

  1. Check your endpoint is publicly accessible (HTTPS required)
  2. Verify no firewall blocking our IP range
  3. Check webhook delivery logs in dashboard

Signature Verification Failing

  1. Ensure you're using the correct webhook secret
  2. Verify you're computing HMAC on the raw request body
  3. Don't parse/modify the JSON before verification

Timeouts

  1. Return 200 OK within 10 seconds
  2. Process work asynchronously
  3. Use a message queue for heavy processing

Next Steps

Built with ❤️ by Rach Finance