Skip to main content
Because your webhook URL is public, anyone could try to POST fake events to it. BillStack signs every webhook with your secret key so you can confirm a request really came from us and was not altered in transit. Verify the signature before you trust an event. Each webhook arrives with these headers: Verify x-wiaxy-signature-256. It is computed over the exact body of each request, so it proves both authenticity (only someone with your secret key could produce it) and integrity (any change to the body invalidates it). To verify:
  1. Read x-wiaxy-timestamp and the raw, unparsed request body.
  2. Build the string "{timestamp}.{rawBody}".
  3. Compute HMAC-SHA256 of that string with your secret key, as hex.
  4. Compare it to x-wiaxy-signature-256 using a constant-time comparison.
  5. Reject the request if the timestamp is older than a few minutes, to stop replays.
Always verify against the raw, unparsed request body : exactly the bytes you received. Re-serialising the JSON (for example JSON.stringify(req.body)) can reorder keys or change whitespace, producing a different signature and a failed check.

The legacy signature

Older integrations may still check x-wiaxy-signature, a static md5(secret_key). Because it never changes between requests, it does not prove the body is intact and is weaker than the HMAC signature. It is still sent for backward compatibility, but new integrations should verify x-wiaxy-signature-256 instead.
Both headers are sent on every webhook, so you can migrate from the legacy signature to the new one without any change on our side : just start verifying x-wiaxy-signature-256.