Documentation Index
Fetch the complete documentation index at: https://docs.khaime.com/llms.txt
Use this file to discover all available pages before exploring further.
Webhook Signature Verification
Every webhook request includes an X-Khaime-Signature header containing an HMAC-SHA256 hash of the raw request body, signed with your webhook secret.
Always verify signatures before processing webhooks to prevent spoofed events.
How It Works
- Khaime computes
HMAC-SHA256(webhook_secret, raw_request_body)
- Sends the hex digest in
X-Khaime-Signature
- You recompute the same hash using the raw request body and compare
Use the raw request body (not a re-serialized version) for signature verification. Re-serializing JSON can change key ordering or whitespace, causing verification to fail.
Implementation
const crypto = require('crypto');
function verifyWebhook(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In Express, use express.raw() to get the raw body:
app.post('/webhooks/khaime', express.raw({ type: 'application/json' }), (req, res) => {
const rawBody = req.body.toString();
const signature = req.headers['x-khaime-signature'];
if (!verifyWebhook(rawBody, signature, process.env.KHAIME_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const payload = JSON.parse(rawBody);
// Process event...
res.status(200).send('OK');
});
Use constant-time comparison (timingSafeEqual, compare_digest, hash_equals) to prevent timing attacks. Never use === or == for signature comparison.