Verify Callbacks
Best practices for handling Payzava webhook callbacks securely
Always verify callback data by calling the retrieve endpoint. Never trust callback data alone.
Why verify?
- Callback query parameters could theoretically be spoofed
- Callbacks may fire multiple times
- The retrieve endpoint gives you the authoritative current status
Correct callback handling pattern
const express = require("express");
const axios = require("axios");
const app = express();
app.post("/webhooks/payzava", async (req, res) => {
// Step 1: Respond immediately with 200 OK
res.status(200).send("OK");
// Step 2: Extract transaction ID from query params
const { transactionId, status } = req.query;
if (!transactionId) {
console.error("Missing transactionId in callback");
return;
}
// Step 3: Verify status via the retrieve endpoint
try {
const response = await axios.get(
`https://sandbox.payzava.com/cp/api/v1/payment/retrieve/${transactionId}`,
{
headers: {
"x-api-key": process.env.PAYZAVA_API_KEY,
},
}
);
const { status: verifiedStatus } = response.data.data;
// Step 4: Process based on verified status
switch (verifiedStatus) {
case "Completed":
// Fulfill the order, credit the user, etc.
await fulfillOrder(transactionId);
break;
case "Cancelled":
// Mark payment as failed
await markPaymentFailed(transactionId);
break;
case "Processing":
// Still processing, do nothing yet
break;
}
} catch (error) {
console.error("Failed to verify callback:", error.message);
}
});
app.listen(3000);
Best practices
-
Respond quickly — Always return
200 OKbefore doing any processing. This prevents callback timeouts. -
Verify via retrieve — Never take action based solely on callback query parameters. Always verify with the retrieve endpoint.
-
Handle duplicates — The same callback may be sent multiple times. Use the
transactionIdto check if you have already processed this status change. -
Log everything — Keep a log of all callbacks received for debugging purposes.
What happens if a callback fails?
If your server does not respond within the timeout window (10 seconds), the callback is considered failed. However:
- The actual transaction is not affected. The payment, payout, or refund will still proceed normally.
- Payzava may retry the callback, but this is not guaranteed.
- You should always poll the retrieve endpoint if you suspect you missed a callback.