Skip to main content

Securing Webhooks

Truedy signs every webhook request so you can confirm:
  1. The request really came from Truedy
  2. The payload wasn’t modified in transit
  3. The request isn’t a replay of an older delivery
Never process a webhook payload without verifying its signature first. Skipping verification lets any attacker fake events to your server.

Headers sent with every request

Signature algorithm (step by step)

  1. Read the raw request body bytes exactly as received — do not parse JSON first.
  2. Extract X-Truedy-Timestamp and X-Truedy-Signature.
  3. Build the signed message: "{timestamp}.{raw_body_as_string}"
  4. Compute HMAC-SHA256(key=webhook_secret, message=signed_message) and hex-encode it.
  5. Compare with X-Truedy-Signature using a constant-time comparison.
  6. Reject if the timestamp is more than 5 minutes old (replay protection).

Implementation examples

Where to find your webhook secret

  1. Open the Truedy dashboard → Settings → Webhooks
  2. Select (or create) your webhook endpoint
  3. Copy the Signing Secret — it looks like whsec_...
Store it as an environment variable (TRUEDY_WEBHOOK_SECRET). Never hardcode it in source files.

Security checklist

Always use HTTPS — never accept webhooks over plain HTTP in production
Read the raw body bytes before parsing JSON — parsers may normalize whitespace and break HMAC
Reject stale timestamps (>5 min old) to block replay attacks
Use constant-time comparison (timingSafeEqual / compare_digest) — never === on signatures
Return 2xx immediately after verification — process asynchronously in a background job
Store your webhook secret in an environment variable, not in source code
Treat all payload fields as untrusted input — validate types and handle missing fields

Troubleshooting signature failures

Next steps

Available Webhooks

Full event catalogue and payload shapes

Error Handling & Retries

Idempotent receiver runbook