Skip to main content
DocsWebhooksSecurity & Verification

Security & Verification

Every webhook delivery includes cryptographic headers so you can verify that the request came from Staffify and has not been tampered with.

Request Headers

HeaderDescription
X-Webhook-SignatureHMAC-SHA256 signature in the format sha256=<hex>
X-Webhook-TimestampUnix timestamp (seconds) when the webhook was sent
X-Webhook-EventThe event type (e.g., ticket.created)
X-Webhook-DeliveryUnique delivery ID for deduplication and tracking
User-AgentStaffify-Webhooks/1.0
Content-Typeapplication/json

Verifying Signatures

The signature is computed as: HMAC-SHA256(secret, timestamp + "." + raw_body)

Node.js

const crypto = require('crypto');

function verifyWebhookSignature(req, secret) {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const body = JSON.stringify(req.body);

  // Reject if timestamp is older than 5 minutes (replay protection)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    return false;
  }

  // Compute expected signature
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(timestamp + '.' + body)
    .digest('hex');

  // Constant-time comparison to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Python

import hmac
import hashlib
import time
import PrevNextNav from '../../_components/PrevNextNav';

def verify_webhook(headers, body, secret):
    signature = headers.get('X-Webhook-Signature', '')
    timestamp = headers.get('X-Webhook-Timestamp', '')

    # Reject if timestamp is older than 5 minutes
    if abs(time.time() - int(timestamp)) > 300:
        return False

    # Compute expected signature
    message = f"{timestamp}.{body}"
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

Important

  • Always verify the signature before processing any webhook payload.
  • Use constant-time comparison to prevent timing attacks.
  • Check the timestamp to reject replayed requests older than 5 minutes.
Webhook Security & Verification