Receive real-time HTTP callbacks for payment completions, refunds, disputes, and settlements. Learn how to verify signatures and handle events reliably.
Webhooks let Axra push payment events to your server the moment they happen, so you never need to poll the API to check whether a payment succeeded. When a payment event occurs — a charge completes, a dispute opens, or funds settle — Axra sends an HTTP POST request to the webhookUrl you configured in your business profile. Because many payment flows (like 3DS redirects or card network clearing) are asynchronous, you should always confirm payment status through webhooks rather than relying solely on the response from a charge request.
Fires when a cardholder opens a dispute (chargeback). The full charge amount is debited from your account immediately, plus a non-refundable dispute fee.
Fires when a dispute is resolved. If you win, the charge amount is re-credited to your account (the dispute fee is not refunded). If you lose, no further changes occur — the funds were already debited.
Fires when a hosted checkout / payment-link session is completed. source identifies the originator (payment_link, invoice, etc.) and sourceId is the originating resource ID.
Fires across the payout lifecycle for outbound local-rail payouts. data.object is the same shape as GET /v1/business/payouts/{id}. Fulfill or reconcile your records on payout.settled; reverse on payout.failed.
Always verify the X-Axra-Signature header before processing a webhook. Without verification, any party can send requests to your endpoint and trigger side effects in your system.
To verify a webhook:
1
Get your webhook secret
Find your webhookSecret in the Axra dashboard under Settings → API Keys. Store it as an environment variable — never hardcode it.
2
Compute the expected signature
Compute an HMAC-SHA256 digest of the raw request body (the bytes as received, before any JSON parsing) using your webhookSecret as the key.
3
Compare using constant-time equality
Compare the computed digest to the value in the X-Axra-Signature header using a constant-time comparison function. This prevents timing attacks.
4
Reject if signatures do not match
Return a 401 Unauthorized response immediately. Do not process the event.
const crypto = require('crypto');function verifyWebhookSignature(rawBody, signature, webhookSecret) { const expectedSignature = crypto .createHmac('sha256', webhookSecret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature, 'hex'), Buffer.from(expectedSignature, 'hex'), );}app.post('/webhook', (req, res) => { const signature = req.headers['x-axra-signature']; const rawBody = JSON.stringify(req.body); if (!verifyWebhookSignature(rawBody, signature, process.env.AXRA_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const { event, data } = req.body; switch (event) { case 'payment.completed': // Update your order status break; case 'payment.settled': // Funds are now available break; case 'payment.disputed': // Alert your fraud team break; } res.status(200).send('OK');});
Use the raw request body bytes for signature computation — not a re-serialized version of the parsed JSON. JSON serialization is not guaranteed to be deterministic, and any whitespace difference will cause verification to fail.
Axra considers a delivery successful when your endpoint responds with an HTTP 2xx status code within 30 seconds. If delivery fails, Axra retries with the following schedule:
Attempt
Delay after failure
1
Immediate
2
30 seconds
3
60 seconds
4
90 seconds
5
120 seconds
After 5 failed attempts, the webhook delivery is marked permanently failed. You can review failed deliveries and trigger manual redelivery in the Axra dashboard → Webhooks → Delivery Logs.
Return 200 quickly — acknowledge receipt immediately, then process the event in a background job. Long-running handlers risk timeouts and unnecessary retries.
Handle duplicates — network retries mean your endpoint may receive the same event more than once. Use paymentId as an idempotency key to ensure you process each event exactly once.
Always verify signatures — reject any request where X-Axra-Signature does not match your computed value.
Use HTTPS in production — plain HTTP webhook URLs are rejected for live-mode credentials.
Use ngrok during local development — run ngrok http 3000 to get a public URL that tunnels to your local server.