Complete guide to webhooks, debugging, and real-time event monitoring with HookMetry
Your generic HMAC SHA-256 signature logic consistently fails when validating custom integrations.
Copy-paste verified examples. Use the tab that matches your stack.
const crypto = require('crypto');
app.post('/webhooks/custom', express.raw({ type: '*/*' }), (req, res) => {
const receivedSig = req.headers['x-webhook-signature'] || req.headers['x-signature'];
if (!receivedSig) return res.status(400).send('No signature header');
// Check with sender: is the signature hex or base64?
const encoding = 'hex'; // change to 'base64' if required by the provider
const expectedSig = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(req.body)
.digest(encoding);
// Timing-safe comparison — both buffers must have the same encoding
let valid = false;
try {
const a = Buffer.from(receivedSig, encoding);
const b = Buffer.from(expectedSig, encoding);
valid = a.length === b.length && crypto.timingSafeEqual(a, b);
} catch { valid = false; }
if (!valid) return res.status(401).send('Signature mismatch');
const payload = JSON.parse(req.body);
res.status(200).json({ ok: true });
});Determine encoding → read raw payload → generate HMAC → 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.