Skip to main content
Every webhook request Bondify sends to your endpoint includes an X-Bondify-Signature header. This header contains an HMAC-SHA256 hex digest of the raw request body, computed using your project’s Secret Key. Verifying this signature before processing any event is the single most important security step in your webhook integration — it guarantees that the request came from Bondify and that the payload has not been tampered with in transit.

How signatures work

Bondify generates the signature with the following steps:
  1. Takes the raw request body as a UTF-8 byte string (exactly as received over the wire, before any JSON parsing)
  2. Computes HMAC-SHA256(rawBody, secretKey)
  3. Hex-encodes the resulting digest
  4. Sends the result in the X-Bondify-Signature request header
To verify, you perform the same computation on your side and compare your result to the value in the header. If they match, the request is authentic.
Always use a constant-time comparison function — crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python, or hash_equals in PHP — when comparing signatures. Using ===, ==, or any ordinary string equality check leaks timing information that an attacker can exploit to forge signatures.

Verification examples

import crypto from 'crypto';
import express from 'express';

function verifyWebhookSignature(
  body: string,         // raw request body as string
  signature: string,    // X-Bondify-Signature header value
  secret: string        // your BONDIFY_SECRET_KEY
): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your Express route:
app.post('/webhooks', express.raw({ type: '*/*' }), (req, res) => {
  const sig = req.headers['x-bondify-signature'] as string;
  if (!verifyWebhookSignature(req.body.toString(), sig, process.env.BONDIFY_SECRET_KEY!)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  // safe to process
  res.status(200).end();
});

Finding your Secret Key

Your project’s Secret Key is available in the Settings tab of your project in the Bondify dashboard. Store it as an environment variable (for example, BONDIFY_SECRET_KEY) and never hard-code it or commit it to source control.
If you suspect your Secret Key has been compromised, you can rotate it immediately from the project settings page. After rotating, update your environment variable and redeploy — old signatures computed with the previous key will stop passing verification.

Use the raw body for verification

Read the raw request body bytes before parsing JSON, and use that raw buffer or string as input to your HMAC function. In some frameworks (such as Express with express.json() middleware), the body is automatically parsed and re-serialized, which can subtly alter whitespace or key ordering and cause your computed signature to diverge from Bondify’s. Using express.raw({ type: '*/*' }) instead (as shown in the Node.js example above) gives you the original bytes.

Full verification flow

1

Receive the raw request body

Configure your framework to give you the raw byte buffer or string before any JSON parsing takes place.
2

Read the signature header

Extract the value of the X-Bondify-Signature header from the incoming request.
3

Compute the expected signature

Run HMAC-SHA256(rawBody, BONDIFY_SECRET_KEY) and hex-encode the result.
4

Compare using a constant-time function

Use timingSafeEqual, compare_digest, or hash_equals to compare your computed value against the header value. Return 401 if they do not match.
5

Parse and process the event

Only after a successful signature check, parse the JSON body and handle the event. See the Events reference for payload schemas.