Verifying Signatures
Validate that webhook requests came from Vitable using HMAC-SHA512 signatures.
Every webhook request includes an HMAC-SHA512 signature so you can verify it came from Vitable. The signature is computed over the timestamp and payload using your webhook secret key.
To get your webhook secret key, reach out to our team. Each webhook subscription has its own secret key — store it securely and never expose it in client-side code.
Headers
Section titled “Headers”X-Vitable-Signature: sha512=<signature>X-Vitable-Timestamp: <unix_timestamp>Python
Section titled “Python”import hmacimport hashlibimport time
def verify_webhook(payload: str, signature_header: str, timestamp_header: str, secret_key: str) -> bool: # Reject requests older than 5 minutes (prevents replay attacks) timestamp = int(timestamp_header) if abs(time.time() - timestamp) > 300: return False
# Reconstruct the expected signature message = f"{timestamp}.{payload}" expected = "sha512=" + hmac.new( secret_key.encode("utf-8"), message.encode("utf-8"), hashlib.sha512, ).hexdigest()
return hmac.compare_digest(signature_header, expected)Node.js
Section titled “Node.js”import crypto from "node:crypto"
function verifyWebhook(payload, signatureHeader, timestampHeader, secretKey) { // Reject requests older than 5 minutes const timestamp = parseInt(timestampHeader, 10) if (Math.abs(Date.now() / 1000 - timestamp) > 300) { return false }
// Reconstruct the expected signature const message = `${timestamp}.${payload}` const expected = "sha512=" + crypto.createHmac("sha512", secretKey).update(message).digest("hex")
return crypto.timingSafeEqual( Buffer.from(signatureHeader), Buffer.from(expected) )}