Verifying Signatures
Confirm that a webhook delivery genuinely came from Audienceful.
Every delivery is signed so you can confirm it genuinely came from Audienceful and wasn't tampered with or replayed. Verify the signature on each incoming request before trusting its contents.
The signature header
Each delivery carries an X-Audienceful-Signature header containing a timestamp and a signature:
X-Audienceful-Signature: t=1751630400,v1=<hex hmac-sha256>
t— the Unix timestamp (seconds) when the delivery was signed.v1— the signature: the lowercase hexHMAC-SHA256of the string{t}.{raw_request_body}, keyed with your endpoint's signingsecret.
How to verify
- Read the raw request body and the
X-Audienceful-Signatureheader. - Parse
tandv1out of the header. - Reject the request if
tis more than 5 minutes away from your current time (replay protection). - Compute
HMAC-SHA256(secret, "{t}.{raw_body}")as lowercase hex. - Compare your computed value against
v1using a constant-time comparison. If they match, the request is authentic.
Your signing secret (whsec_…) is returned once, when you create the endpoint.
Verify against the raw request body bytes, exactly as received — before any JSON parsing or re-serialization. Re-serializing the body (even reformatting whitespace) changes it, and the signature will no longer match. Most frameworks expose the raw body separately from the parsed JSON.
Examples
import hashlib, hmac, time
def verify_signature(secret: str, raw_body: str, signature_header: str, tolerance: int = 300) -> bool:
parts = dict(kv.split("=", 1) for kv in signature_header.split(","))
timestamp = int(parts["t"])
# Reject stale timestamps (replay protection).
if abs(time.time() - timestamp) > tolerance:
return False
expected = hmac.new(
secret.encode(), f"{timestamp}.{raw_body}".encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, parts["v1"])The same signature scheme is used by the automation "Send Webhook" action, signed with that action's own secret — so the same verification code works there too.