Check the webhook signature

The owlpay-signature header included in each signed event contains a timestamp and one signature. The timestamp is prefixed by t=, and signature is prefixed by a scheme. Scheme start with v.


Note that newlines have been added for clarity, but a real owlpay-signature header is on a single line.

OwlPay generates signatures using a hash-based message authentication code (HMAC) with SHA-256.

We will provide official libraries to verify webhook signature, but before that you can create a custom solution by following these steps.

Step 1: Extract the timestamp and signatures from the header

Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair.

The value for the prefix t corresponds to the timestamp, and v1 corresponds to the signature.

Step 2: Prepare the signed_payload string

The signed_payload string is created by concatenating:

The timestamp (as a string)
The character .
The actual JSON payload (that is, the request body)

Step 3: Determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the signed_payload string as the message.

Step 4: Compare the signatures

Compare the signature (or signatures) in the header to the expected signature.

Code example for PHP:

$requestHeader = 't=1689066169,v1=e997b87453fb8923ae9c02faf45fe5fff60148d7a244896e0b359c96aa4825a0';
$explodedList = explode(',', $requestHeader);
$signaturesData = [];

foreach ($explodedList as $exploded) {
  $signaturesData[] = explode('=', $exploded);

$t = $signaturesData[0][1];
$v = $signaturesData[1][1];

$request_json = '{"uuid":"att_c0d3d7cda1e2175faa701dfd4a9b85355a3c9630","api_version":"1.0.0","is_test":1,"observation":"owlpay.received_order","data":{"order":{"xxx"}}}';

$hash = \hash_hmac('sha256', "$t.$request_json", 'whs_xxxxxxx');

if ($hash === $v) {
  // signature check pass.