> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cashweb.cash/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Security

> Signature verification, replay controls, and handler hardening guidelines.

## 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

```js theme={null}
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

```python theme={null}
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.
