Webhooks
Verify signatures
Check that a request comes from AlphaCount and was not replayed.
Every request carries
X-AlphaCount-Signature: t=1791374400,v1=3f2a…t is the time of signing in Unix seconds; v1 is the hex HMAC-SHA256 of "<t>.<body>" — the timestamp, a dot and
the raw body bytes as received — keyed with the webhook's secret.
- Compute the HMAC over the raw bytes. Do not parse and re-serialise the JSON first.
- Compare in constant time.
- Refuse a timestamp more than 5 minutes away from your clock — that stops a recorded request from being sent again.
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
parts = dict(part.split("=", 1) for part in header.split(","))
timestamp, signature = parts.get("t", ""), parts.get("v1", "")
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > tolerance:
return False
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)Rotating the secret
Rotate the secret in the app when it may have leaked. The new one is shown once; requests are signed with it from then on.