Skip to main content

Webhook Validation

Your server should verify that Refersion is the service that sent a webhook before accepting the incoming data. This is important for securing sensitive data and to protect your server.

Current Refersion webhook deliveries are signed by Svix. Each request includes svix-id, svix-timestamp, and svix-signature headers. Verify all three values with a Svix SDK before processing the request; the timestamp check also protects your endpoint from replay attacks.

To verify a webhook was sent from Refersion, you'll need your Webhook Signing Secret. You can find this in your account by navigating to Account > Settings > Webhooks. Click to show the secret and store it somewhere safe on your server for validation.

Validate current Svix deliveries

Pass the unmodified request body and the Svix headers to the SDK. Parsing or re-serializing the body before verification changes the signed bytes and causes verification to fail.

Here is a sample using the Svix JavaScript SDK:

import { Webhook } from "svix";

const secret = process.env.REFERSION_WEBHOOK_SIGNING_SECRET;
const webhook = new Webhook(secret);

// `rawBody` must contain the request body exactly as Refersion sent it.
const event = webhook.verify(rawBody, {
"svix-id": request.headers["svix-id"],
"svix-timestamp": request.headers["svix-timestamp"],
"svix-signature": request.headers["svix-signature"],
});

// Process the verified event.

Treat a missing header or any exception from verify() as a failed validation and return a 400 response. Svix SDKs apply a five-minute timestamp tolerance by default.

Legacy compatibility deliveries

Some legacy webhook deliveries use an HMAC-SHA256 signature in the X-Refersion-Hmac-Sha256 header. Only use this validation path when your configured integration still receives that header. Compute the hexadecimal HMAC over the unmodified request body and use a constant-time comparison such as PHP's hash_equals().

<?php

$req_headers = getallheaders();
$webhook_signature = $req_headers["X-Refersion-Hmac-Sha256"] ?? "";
$webhook_body = file_get_contents("php://input");
$rfsn_secret = "Your Webhook Signing Secret";

$my_signature = hash_hmac('sha256', $webhook_body, $rfsn_secret);

// hash_equals() compares in constant time, so it does not leak the signature byte by byte.
if (!hash_equals($my_signature, $webhook_signature)) {
exit;
} else {
// Do something with the webhook data
}