What Pruva sends
Every delivery is a POST with two headers and a JSON body:
The signing secret is the
whsec_... value shown once when you created the webhook in Settings.
The steps
1
Read the raw body
Capture the request body as raw bytes, before any JSON parsing. The signature is over the exact bytes sent; re-serialized JSON may differ and will fail to verify.
2
Recompute the signature
Compute
HMAC_SHA256(secret, timestamp + "." + rawBody) and hex encode it.3
Compare in constant time
Compare your value to
X-Pruva-Signature with a constant time comparison, not ==, to avoid leaking timing information.4
Check the timestamp is recent
Reject deliveries whose timestamp is far from now, for example more than five minutes old, so a captured request cannot be replayed later.
5
Then parse and act
Only after the signature and timestamp pass, parse the JSON and handle the event.