Verify webhook signatures (HMAC-SHA256)

Cryptographically verify that an incoming webhook came from VoxReach.

01

Set a signing secret

  • At /integrations/webhooks → click your webhook → Secret field.
  • Generate a random 32-char string. Save it on both sides — VoxReach signs with it, you verify with it.
02

Headers we send

  • X-VoxReach-Event: call.ended
  • X-VoxReach-Signature: sha256=
  • Content-Type: application/json
03

Verify in Node.js

  • const crypto = require('node:crypto');
  • const expected = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET).update(rawBody).digest('hex');
  • const received = req.headers['x-voxreach-signature'].replace('sha256=', '');
  • if (crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) { /* valid */ }
04

Verify in PHP

  • $expected = hash_hmac('sha256', $rawBody, $secret);
  • $received = str_replace('sha256=', '', $_SERVER['HTTP_X_VOXREACH_SIGNATURE']);
  • if (hash_equals($expected, $received)) { /* valid */ }
05

Verify in Python

  • import hmac, hashlib
  • expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
  • received = request.headers['X-VoxReach-Signature'].replace('sha256=','')
  • if hmac.compare_digest(expected, received): pass
06

Replay attack prevention

  • VoxReach also sends X-VoxReach-Timestamp.
  • Reject any webhook older than 5 minutes — replays a malicious actor would attempt.

Still stuck?

Email hello@voxreach.com.au — we reply within 2 business hours during AEST hours.

Open a ticket