Signature Verification
Every webhook request includes two headers:
| Header | Contents |
|---|---|
x-autorev-signature | HMAC-SHA256 signature, e.g. sha256=abc... |
x-autorev-timestamp | Timestamp of the delivery |
The signature is an HMAC-SHA256 digest computed with your subscription's signing_secret (the whsec_... value returned once at creation) over the string:
timestamp + "." + rawBody
Two rules that prevent broken or insecure verifiers:
- Sign over the raw request body, the exact JSON string as received, not a re-serialized version of the parsed object. Re-serializing can reorder keys or change whitespace and the signature will not match.
- Compare with
timingSafeEqual, never==. A plain string comparison leaks timing information.
Node.js example
const crypto = require('crypto')
function verifyWebhook(req, signingSecret) {
const timestamp = req.headers['x-autorev-timestamp']
const sigHeader = req.headers['x-autorev-signature'] // "sha256=abc..."
const body = req.rawBody // raw JSON string, NOT the parsed object
const expected = 'sha256=' + crypto
.createHmac('sha256', signingSecret)
.update(`${timestamp}.${body}`)
.digest('hex')
const a = Buffer.from(sigHeader)
const b = Buffer.from(expected)
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
Note the length check before crypto.timingSafeEqual: the function throws if the buffers differ in length, so guard it and treat a length mismatch as a failed verification.
Using it in a webhook handler
app.post('/webhooks/autorev', (req, res) => {
if (!verifyWebhook(req, process.env.AUTOREV_SIGNING_SECRET)) {
return res.status(401).send('Invalid signature')
}
// Process event...
res.status(200).json({ received: true })
})
Your framework must expose the raw body (for example, an Express raw-body middleware that stores it on req.rawBody) so the digest is computed over exactly the bytes AutoRev sent.
Where the secret comes from
Only the Webhook Subscriptions API returns a signing secret, and only once, at creation. The legacy per-receptionist webhook_url receives events too, but its secret is not retrievable via the API, so signature verification is only practical on subscriptions. If you lose a secret, delete the subscription and create a new one.