Skip to content

Webhook Signatures & Security

Biosyn provides real-time HTTP webhook notifications for attendance and access events. When a user interacts with a device (check-in, check-out, door open), Biosyn instantly pushes an event payload to your configured webhook endpoint.


Webhook Signature Verification

To ensure that incoming webhooks originate from Biosyn and have not been tampered with, Biosyn signs every request using HMAC SHA-256.

Webhook Headers

Every webhook HTTP request includes the following header:

http
X-WDMS-Signature: sha256=a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e

Signature Generation Algorithm

  • Algorithm: HMAC-SHA256
  • Secret Key: Your Location Webhook Secret Key (webhook_secret)
  • Message: Exact JSON request body payload (raw string)

Code Verification Examples

python
import hmac
import hashlib
import json

def verify_biosyn_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool:
    if not signature_header or not signature_header.startswith("sha256="):
        return False

    provided_signature = signature_header.split("sha256=")[1]

    expected_signature = hmac.new(
        secret.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected_signature, provided_signature)
javascript
const crypto = require("crypto");

function verifyBiosynWebhook(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !signatureHeader.startsWith("sha256=")) {
    return false;
  }

  const providedSig = signatureHeader.replace("sha256=", "");
  const expectedSig = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(providedSig, "utf-8"),
    Buffer.from(expectedSig, "utf-8"),
  );
}
php
<?php

function verifyBiosynWebhook(string $rawBody, string $signatureHeader, string $secret): bool
{
    if (empty($signatureHeader) || !str_starts_with($signatureHeader, 'sha256=')) {
        return false;
    }

    $providedSig = substr($signatureHeader, 7);
    $expectedSig = hash_hmac('sha256', $rawBody, $secret);

    return hash_equals($expectedSig, $providedSig);
}

Webhook Event Payload Structure

Event: attendance

json
{
  "event": "attendance",
  "payload": {
    "location_id": 1,
    "device_sn": "AFK921400123",
    "pin": 10042,
    "card_no": "1234567890",
    "verified_type": 4,
    "door_id": 1,
    "event": 0,
    "status": 0,
    "timestamp": "2026-08-26T10:30:00Z",
    "index": 5978,
    "site_code": 0,
    "dev_id": 1,
    "mask_flag": true,
    "temperature": 36.5,
    "conv_temperature": 97.7,
    "created_at": "2026-08-26T10:30:01Z"
  }
}

Webhook Delivery & Retry Policy

  • Max Retries: 3 attempts
  • Backoff Strategy: Exponential backoff (1s, 2s, 4s)
  • Timeout: 30 seconds per attempt
  • Accepted HTTP Response: Any 2xx status code (e.g. 200 OK, 204 No Content)

Enterprise Biometric Gateway Infrastructure