Complete guide to webhooks, debugging, and real-time event monitoring with HookMetry
Razorpay signature validation fails with X-Razorpay-Signature mismatch errors.
Copy-paste verified examples. Use the tab that matches your stack.
const crypto = require('crypto');
app.post('/webhooks/razorpay', express.raw({ type: 'application/json' }), (req, res) => {
const receivedSig = req.headers['x-razorpay-signature'];
if (!receivedSig) return res.status(400).send('Missing signature header');
// Must be 'hex' encoding — NOT 'base64'. This is the #1 mistake.
const expectedSig = crypto
.createHmac('sha256', process.env.RAZORPAY_WEBHOOK_SECRET)
.update(req.body) // Buffer from express.raw()
.digest('hex');
try {
const a = Buffer.from(receivedSig, 'hex');
const b = Buffer.from(expectedSig, 'hex');
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('Signature mismatch');
}
} catch {
return res.status(401).send('Signature mismatch');
}
const event = JSON.parse(req.body);
console.log('Razorpay event:', event.event);
res.status(200).json({ received: true });
});Save secret → capture raw body → hash with hex → timing safe compare.
Works with webhooks and other async event systems (including AI callbacks).
Instead of guessing, inspecting the exact payload and headers can help debug faster. Tools like Hookmetry support this workflow.
Try the free webhook testerWas this page helpful?
Your feedback helps us improve the docs.