Skip to main content

Verification Headers

  • X-CW-Webhook-Timestamp
  • X-CW-Webhook-Signature

Signature Algorithm

  1. Compute body_hash = SHA256(raw_request_body) as lowercase hex.
  2. Build signing string: "<timestamp>.<event_type>.<body_hash>".
  3. Compute HMAC_SHA256(signing_string, webhook_signing_secret) as lowercase hex.
  4. Compare against X-CW-Webhook-Signature in constant time.

Node.js Example

import crypto from "crypto";

function verifyWebhook({ timestamp, eventType, rawBody, signature, secret }) {
  const bodyHash = crypto.createHash("sha256").update(rawBody).digest("hex");
  const signingPayload = `${timestamp}.${eventType}.${bodyHash}`;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(signingPayload)
    .digest("hex");

  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Python Example

import hashlib
import hmac

def verify_webhook(timestamp: str, event_type: str, raw_body: bytes, signature: str, secret: str) -> bool:
    body_hash = hashlib.sha256(raw_body).hexdigest()
    signing_payload = f"{timestamp}.{event_type}.{body_hash}".encode("utf-8")
    expected = hmac.new(secret.encode("utf-8"), signing_payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Replay Protection

  • Reject events older than your allowed timestamp skew window.
  • Store processed event IDs and ignore duplicates.
  • Keep a durable event-processing audit trail.