Signature verification
Tesouro can sign webhook deliveries with HMAC-SHA512 so you can verify a request came from Tesouro and wasn’t tampered with. Signing is opt-in per subscription - unsigned by default. Once enabled, every delivery to that subscription includes the three headers below.
To enable signing for your subscription, contact your Tesouro implementation team.
| Header | Example value | Description |
|---|
x-tesouro-signature | t=1746673883,v1=A1B2C3...DEF0 | Signature header. v1=<hex> is the 128-character uppercase hex HMAC-SHA512 digest. t=<unix-seconds> is the send-time Tesouro stamped on the request, included in the signed input - use it for replay-window checks (see Replay protection). |
x-tesouro-key-id | prod-key-2026-01 | Identifier of the signing key Tesouro used. Use it to select the matching shared secret - Tesouro supports overlapping keys during rotation. |
x-tesouro-algorithm | hmac-sha512 | Algorithm used. Currently always hmac-sha512. |
Computing the signature
signed_input = "{t}.{request_body}"
v1 = HEX( HMAC-SHA512( secret, signed_input ) )
{t} is the unix-seconds value from x-tesouro-signature. {request_body} is the raw request body bytes, byte-for-byte as received - don’t re-serialize or reformat the JSON before hashing. Compare case-insensitively (the digest is uppercase on the wire).
Verification steps
- Extract
t=<unix-seconds> and v1=<hex> from the x-tesouro-signature header.
- Look up the shared secret for the key id in
x-tesouro-key-id.
- Construct
signed_input = "{t}.{raw_body}".
- Compute
HEX(HMAC-SHA512(secret, signed_input)).
- Reject with
401 if the computed digest doesn’t match v1.
Example using openssl:
SECRET="<your shared secret>"
T="<unix-seconds value from x-tesouro-signature>"
EXPECTED=$( { printf '%s.' "$T"; cat request-body.json; } | openssl dgst -sha512 -hmac "$SECRET" -hex | awk '{print toupper($2)}')
echo "$EXPECTED"
If signing is enabled for your subscription, always verify the signature before processing the event.
Replay protection
After verifying the signature, also check that the request is fresh:
- Reject stale requests. Compare
t=<unix-seconds> from x-tesouro-signature to the current time and reject anything older than a small window (Tesouro recommends 5 minutes).
- Deduplicate on
deliveryId. Maintain a cache of recently-seen deliveryId values from the envelope and reject any request whose deliveryId you’ve already processed.
Secret rotation
Signing secrets can be rotated without downtime:
- Add the new secret before removing the old one.
- During the rotation period, accept requests signed by either key - use
x-tesouro-key-id to select the matching secret per request.
- Remove the old secret only after all in-flight webhooks finish.
Contact Tesouro support to rotate your webhook signing secret.
Endpoint validation
In addition to signature verification:
- Register only HTTPS endpoints; plain HTTP isn’t supported.
- Where possible, restrict your webhook handler to known Tesouro source IPs.
- Return
401 for requests that fail validation.
Additional options
Tesouro also supports mutual TLS (mTLS) - contact the implementation team to enable it.