Webhook Integration
Receive real-time transaction status updates (SUCCESS | FAILED | EXPIRED | PENDING) via HTTP POST.
Payload (Example)
json
{
"transactionId": "abcf4dd4-b7b1-460d-a309-250981498458",
"md5": "0335ae49...",
"status": "SUCCESS",
"amount": "1",
"currency": "840",
"requestLog": {
"metaData": {
"meta": { "orderId": "ORD-123" },
"amount": 1,
"currency": 840,
"expiredAfter": 30000
}
},
"createdAt": "2025-08-03T15:11:13.483Z"
}Key fields: transactionId | status | amount | currency | requestLog.metaData.meta | createdAt
Security Headers
x-timestamp: <ISO8601>
x-signature: sha256=<hmac>
content-type: application/jsonSignature = HMAC_SHA256( ${timestamp}.${rawBody} , WEBHOOK_SECRET )
Minimal Node.js Handler
js
import crypto from "crypto";
import express from "express";
const app = express();
app.use(express.json());
function verify(req) {
const ts = req.headers["x-timestamp"];
const sig = req.headers["x-signature"];
const body = JSON.stringify(req.body);
const exp =
"sha256=" +
crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(`${ts}.${body}`)
.digest("hex");
return sig === exp;
}
app.post("/webhook", (req, res) => {
if (!verify(req)) return res.status(401).send("bad sig");
res.send("OK"); // ack fast
queueMicrotask(() => handle(req.body));
});Status Meanings
SUCCESS paid | FAILED declined/error | EXPIRED QR timed out | PENDING awaiting payment
Idempotency
Store processed transactionIds; skip duplicates (retries may occur on 5xx/timeouts).
Quick Checklist
[x] HTTPS [x] Signature verify [x] 200 fast [x] Idempotent [x] Log + monitor
Testing Tip
Use ngrok (ngrok http 3000) and send a manual POST with computed signature.
Related
Last updated: August 10, 2025
