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=a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146eSignature 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
2xxstatus code (e.g.200 OK,204 No Content)