Skip to main content
Dugble signs every webhook request with the signing secret shown when you create or rotate an endpoint. Verify the signature before decoding JSON or applying any side effects.
Use the complete secret, including its whsec_ prefix, as the HMAC key. Do not Base64-decode the characters after the prefix.

Signature contract

The X-Dugble-Signature header has this format:
t is the delivery attempt time in Unix seconds. v1 is the lowercase hexadecimal encoding of an HMAC-SHA256 digest. To calculate the expected digest:
  1. Read the request body as its original bytes. Do not parse and re-serialize it.
  2. Build the signed payload by concatenating the decimal timestamp, one ASCII period (.), and the raw body bytes.
  3. Compute HMAC-SHA256 with the complete endpoint signing secret as the key.
  4. Hex-encode the digest in lowercase.
  5. Compare the received and expected digests with a constant-time function.
  6. Reject timestamps more than five minutes away from your server time.
In bytes, the signed payload is:

TypeScript example

This Express example installs a route-specific raw-body parser. Register it before any application-wide JSON parser that would consume the same request.

Python example

Test vector

Use this deterministic vector to test your implementation. The timestamp is intentionally old, so disable the replay-window check for this fixture only.

Operational guidance

  • Return 400 for a malformed, stale, or invalid signature.
  • Store the event ID with a unique constraint because delivery is at least once.
  • Keep endpoint secrets out of logs, analytics, and error reports.
  • Rotating an endpoint secret immediately makes the newly displayed secret the key for subsequent delivery attempts. Update your receiver before testing it.