Signature verification
Verify the signature on a webhook before you trust its body.
Every delivery is signed so you can verify it came from Capvant. The X-Capvant-Signature header carries an HMAC-SHA256 of the raw request body, keyed with your endpoint's secret:
X-Capvant-Signature: sha256=6c1f0b...Replay protection
Two more headers bind the send time to the body: X-Capvant-Timestamp (unix seconds) and X-Capvant-Signature-256: t=,v1=, where v1 is an HMAC-SHA256 over the string . with the same secret. Verify v1 and refuse deliveries whose timestamp is older than your tolerance (five minutes is the usual choice); a captured delivery then cannot be replayed against you. Retries of the same event carry a fresh timestamp and signature. Capvant never follows a redirect from your endpoint: answer 2xx directly on the registered URL.
Verify (Node)
import { createHmac, timingSafeEqual } from 'crypto';
function verify(rawBody, header, secret) {
const expected = 'sha256=' + createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}Verify (Python)
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(header, expected)Compute the HMAC over the raw bytes before any JSON parsing; re-serialised JSON will not match.
