Use this page for the security and operational rules around webhook delivery:
verify every delivery with X-WEBHOOK-SIGN
respond within the supported timeout window
handle duplicate deliveries safely
process events using updated_at for sequencing
allowlist Truv IPs or configure mTLS when your network requires it
Use Webhook Events only as the event catalog. Use Webhooks for endpoint configuration and payload structure.
Webhook signature verification
Every webhook request from Truv includes an X-WEBHOOK-SIGN header containing an HMAC-SHA256 hash. Use this to verify that requests are authentic and haven’t been tampered with.
How it works
Truv computes an HMAC-SHA256 hash of the raw request body using your Access Secret
The hash is sent in the X-WEBHOOK-SIGN header with a v1= prefix
Your server recomputes the hash and compares it to the header value
Use the raw request body (not parsed JSON) when computing the hash. Parsing and re-serializing may change the byte representation.
Code examples
import hashlib
import hmac
def verify_webhook ( payload : str , signature : str , secret : str ) -> bool :
generated_hash = hmac.new(
key = secret.encode( 'utf-8' ),
msg = payload.encode( 'utf-8' ),
digestmod = hashlib.sha256,
).hexdigest()
expected = f 'v1= { generated_hash } '
return hmac.compare_digest(expected, signature)
const crypto = require ( "crypto" );
const express = require ( "express" );
const bodyParser = require ( "body-parser" );
const app = express ();
app . use ( bodyParser . json ({
verify : ( req , res , buf ) => {
req . rawBody = buf ;
}
}));
function verifyWebhook ( rawBody , signature , secret ) {
const hash = crypto
. createHmac ( "sha256" , secret )
. update ( rawBody )
. digest ( "hex" );
const expected = `v1= ${ hash } ` ;
return signature === expected ;
}
app . post ( "/webhooks/truv" , ( req , res ) => {
const signature = req . headers [ "x-webhook-sign" ];
const isValid = verifyWebhook ( req . rawBody , signature , process . env . TRUV_SECRET );
if ( ! isValid ) {
return res . status ( 401 ). send ( "Invalid signature" );
}
res . status ( 200 ). send ( "OK" );
});
import (
" crypto/hmac "
" crypto/sha256 "
" encoding/hex "
" fmt "
)
func verifyWebhook ( body string , signature string , secret string ) bool {
mac := hmac . New ( sha256 . New , [] byte ( secret ))
mac . Write ([] byte ( body ))
expected := fmt . Sprintf ( "v1= %s " , hex . EncodeToString ( mac . Sum ( nil )))
return hmac . Equal ([] byte ( expected ), [] byte ( signature ))
}
require 'openssl'
def verify_webhook ( body , signature , secret )
digest = OpenSSL :: Digest . new ( 'sha256' )
expected = "v1=" + OpenSSL :: HMAC . hexdigest (digest, secret, body)
Rack :: Utils . secure_compare (expected, signature)
end
using System . Security . Cryptography ;
using System . Text ;
private bool VerifyWebhook ( string body , string signature , string secret )
{
using ( HMACSHA256 hmac = new HMACSHA256 ( Encoding . UTF8 . GetBytes ( secret )))
{
byte [] hashValue = hmac . ComputeHash ( Encoding . UTF8 . GetBytes ( body ));
string expected = "v1=" + BitConverter . ToString ( hashValue )
. Replace ( "-" , "" ). ToLower ();
return expected == signature ;
}
}
Delivery behavior
Truv webhook deliveries follow these operating constraints:
endpoints should return a successful 2xx response within 10 seconds
3xx redirects are accepted
non-success responses trigger retries
unsuccessful deliveries are retried up to 3 times with a 30-second gap between attempts
Respond quickly, acknowledge receipt, and move heavier processing into an asynchronous job or queue.
Ordering and idempotency
Webhook deliveries are asynchronous, so your application should not assume arrival order alone is authoritative.
use the updated_at field to process status changes in sequence
implement idempotency using webhook_id so duplicate deliveries do not trigger duplicate work
fetch fresh data from the API when you need the latest full resource state
Originating IP addresses
Allowlist the current Truv webhook IP addresses if your network requires source filtering:
34.212.57.93
44.224.243.166
52.25.14.79
For the webhook schema and delivery object details, see Webhooks .
Additional authentication options
Beyond webhook signature verification, Truv supports:
Truv-signed certificates for webhook mTLS
client-signed certificates for webhook mTLS
custom headers such as client ID and client secret, configured with Truv
Use mTLS if you need mutual certificate-based authentication for webhook delivery.
Webhook implementation checklist
// Verify signature on the raw body
// Return 200 quickly
// Queue processing asynchronously
// Deduplicate by webhook_id
// Use updated_at for ordering checks