Skip to content

Webhooks Overview

Webhooks enable real-time notifications when important events occur in TruthVouch. Instead of polling the API, your application receives HTTP POST requests whenever alerts are created, policies are violated, or certifications are issued.

What are Webhooks?

A webhook is an HTTP callback that TruthVouch sends to your server when an event occurs.

Example: When a hallucination is detected:

POST https://yourapp.com/webhooks/alerts HTTP/1.1
Content-Type: application/json
X-Signature: hmac-sha256=abcd1234...
{
"id": "evt_...",
"type": "alert.created",
"timestamp": "2024-03-15T10:30:00Z",
"data": {
"alertId": "alert_123",
"severity": "high",
"type": "hallucination",
"message": "The response contains a claim that cannot be verified"
}
}

Your endpoint acknowledges receipt with 200 OK:

HTTP/1.1 200 OK

Creating a Webhook

Via Dashboard

  1. Go to Settings → Webhooks
  2. Click New Webhook
  3. Enter your endpoint URL (must be HTTPS)
  4. Select event types to subscribe to
  5. Click Create

Via API

Terminal window
curl -X POST https://api.truthvouch.com/api/v1/webhooks \
-H "Authorization: Bearer tv_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/events",
"events": [
"alert.created",
"correction.deployed",
"certification.issued"
],
"active": true
}'

Response:

{
"data": {
"id": "whk_abc123",
"url": "https://yourapp.com/webhooks/events",
"events": ["alert.created", "correction.deployed", "certification.issued"],
"active": true,
"createdAt": "2024-03-15T10:00:00Z"
}
}

Webhook Requirements

Your endpoint must:

  1. Be HTTPS — HTTP endpoints are rejected
  2. Respond within 30 seconds — Slower endpoints time out
  3. Return 200-299 status — Any 2xx response is considered successful
  4. Verify the signature — Validate HMAC-SHA256 signature
  5. Handle duplicates — Same event may be delivered multiple times
  6. Be idempotent — Process the same event multiple times safely

Webhook Endpoint Example

Python (Flask)

from flask import Flask, request
import hmac
import hashlib
import json
import os
app = Flask(__name__)
WEBHOOK_SECRET = os.environ["TRUTHVOUCH_WEBHOOK_SECRET"]
@app.route("/webhooks/events", methods=["POST"])
def handle_webhook():
# Verify signature
signature = request.headers.get("X-Signature", "")
body = request.get_data()
expected = "hmac-sha256=" + hmac.new(
WEBHOOK_SECRET.encode(),
body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
return {"error": "Invalid signature"}, 401
# Parse event
event = request.json
if event["type"] == "alert.created":
alert = event["data"]
print(f"Alert created: {alert['severity']} - {alert['message']}")
# Handle alert...
elif event["type"] == "correction.deployed":
correction = event["data"]
print(f"Correction deployed: {correction['id']}")
# Handle correction...
return {"status": "received"}, 200
if __name__ == "__main__":
app.run(port=5000)

Node.js (Express)

import express from 'express';
import crypto from 'crypto';
const app = express();
const WEBHOOK_SECRET = process.env.TRUTHVOUCH_WEBHOOK_SECRET;
app.use(express.raw({ type: 'application/json' }));
app.post('/webhooks/events', (req, res) => {
// Verify signature
const signature = req.headers['x-signature'] || '';
const expected =
'hmac-sha256=' +
crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(signature, expected)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Parse event
const event = JSON.parse(req.body);
if (event.type === 'alert.created') {
const alert = event.data;
console.log(`Alert: ${alert.severity} - ${alert.message}`);
// Handle alert...
} else if (event.type === 'correction.deployed') {
const correction = event.data;
console.log(`Correction: ${correction.id}`);
// Handle correction...
}
res.json({ status: 'received' });
});
app.listen(3000);

Event Types

TruthVouch sends the following events:

EventWhenData
alert.createdHallucination or PII detectedAlert details
alert.resolvedAlert manually resolvedAlert ID, resolution
correction.deployedCorrection publishedCorrection details
certification.issuedContent certifiedCertificate details
certification.revokedCertificate revokedCertification ID
policy.violatedPolicy enforcement action takenPolicy ID, violation reason
scan.completedBatch scan finishedScan results summary

Full event reference →

Signature Verification

Every webhook request includes an X-Signature header with an HMAC-SHA256 signature:

X-Signature: hmac-sha256=abcdef123456789...

To verify:

import hmac
import hashlib
def verify_webhook_signature(body, signature, secret):
expected = "hmac-sha256=" + hmac.new(
secret.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)

Full verification guide →

Retries

If your endpoint doesn’t respond or returns an error:

  1. Immediate retry — After 1 second
  2. Exponential backoff — 2s, 4s, 8s, 16s, 32s delays
  3. Max attempts — 5 retries over ~1 minute
  4. Max window — 72 hours from initial attempt

After 5 failed attempts over 72 hours, the webhook is disabled.

Retry policy details →

Testing Webhooks

Local Development

Use a webhook tunnel (ngrok) to forward requests to your local machine:

Terminal window
# Terminal 1: Start tunnel
ngrok http 5000
# Terminal 2: Register webhook with ngrok URL
curl -X POST https://api.truthvouch.com/api/v1/webhooks \
-H "Authorization: Bearer tv_live_..." \
-d '{
"url": "https://abc123.ngrok.io/webhooks/events",
"events": ["alert.created"]
}'
# Terminal 3: Start your local app
python app.py

Webhook Testing Tools

  1. webhook.site — Inspectable URL for testing
  2. Postman — Mock server for testing
  3. RequestBin — Capture and inspect webhooks
  4. TruthVouch CLI (planned) — Local webhook receiver

Webhook testing guide →

Webhook Management

List Webhooks

Terminal window
curl https://api.truthvouch.com/api/v1/webhooks \
-H "Authorization: Bearer tv_live_..."

Update Webhook

Terminal window
curl -X PATCH https://api.truthvouch.com/api/v1/webhooks/whk_abc123 \
-H "Authorization: Bearer tv_live_..." \
-d '{
"url": "https://newurl.com/webhooks",
"events": ["alert.created", "alert.resolved"],
"active": true
}'

Delete Webhook

Terminal window
curl -X DELETE https://api.truthvouch.com/api/v1/webhooks/whk_abc123 \
-H "Authorization: Bearer tv_live_..."

View Delivery History

Terminal window
curl https://api.truthvouch.com/api/v1/webhooks/whk_abc123/deliveries \
-H "Authorization: Bearer tv_live_..."

Best Practices

  1. Verify signatures — Always validate HMAC-SHA256
  2. Be idempotent — Same event may be delivered multiple times
  3. Respond quickly — Keep handler under 30 seconds
  4. Queue async work — Use a job queue for slow operations
  5. Log deliveries — Store webhook data for debugging
  6. Monitor health — Alert if webhooks fail repeatedly
  7. Use HTTPS — Required for security
  8. Rotate secrets — Regenerate webhook secret quarterly

Webhook Limits

  • Per organization: Up to 100 webhooks
  • Payload size: Max 1MB per event
  • Timeout: 30 seconds
  • Retry period: 72 hours max
  • Event history: Stored for 90 days

Next Steps