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.1Content-Type: application/jsonX-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 OKCreating a Webhook
Via Dashboard
- Go to Settings → Webhooks
- Click New Webhook
- Enter your endpoint URL (must be HTTPS)
- Select event types to subscribe to
- Click Create
Via API
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:
- Be HTTPS — HTTP endpoints are rejected
- Respond within 30 seconds — Slower endpoints time out
- Return 200-299 status — Any 2xx response is considered successful
- Verify the signature — Validate HMAC-SHA256 signature
- Handle duplicates — Same event may be delivered multiple times
- Be idempotent — Process the same event multiple times safely
Webhook Endpoint Example
Python (Flask)
from flask import Flask, requestimport hmacimport hashlibimport jsonimport 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:
| Event | When | Data |
|---|---|---|
alert.created | Hallucination or PII detected | Alert details |
alert.resolved | Alert manually resolved | Alert ID, resolution |
correction.deployed | Correction published | Correction details |
certification.issued | Content certified | Certificate details |
certification.revoked | Certificate revoked | Certification ID |
policy.violated | Policy enforcement action taken | Policy ID, violation reason |
scan.completed | Batch scan finished | Scan results summary |
Signature Verification
Every webhook request includes an X-Signature header with an HMAC-SHA256 signature:
X-Signature: hmac-sha256=abcdef123456789...To verify:
import hmacimport 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)Retries
If your endpoint doesn’t respond or returns an error:
- Immediate retry — After 1 second
- Exponential backoff — 2s, 4s, 8s, 16s, 32s delays
- Max attempts — 5 retries over ~1 minute
- Max window — 72 hours from initial attempt
After 5 failed attempts over 72 hours, the webhook is disabled.
Testing Webhooks
Local Development
Use a webhook tunnel (ngrok) to forward requests to your local machine:
# Terminal 1: Start tunnelngrok http 5000
# Terminal 2: Register webhook with ngrok URLcurl -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 apppython app.pyWebhook Testing Tools
- webhook.site — Inspectable URL for testing
- Postman — Mock server for testing
- RequestBin — Capture and inspect webhooks
- TruthVouch CLI (planned) — Local webhook receiver
Webhook Management
List Webhooks
curl https://api.truthvouch.com/api/v1/webhooks \ -H "Authorization: Bearer tv_live_..."Update Webhook
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
curl -X DELETE https://api.truthvouch.com/api/v1/webhooks/whk_abc123 \ -H "Authorization: Bearer tv_live_..."View Delivery History
curl https://api.truthvouch.com/api/v1/webhooks/whk_abc123/deliveries \ -H "Authorization: Bearer tv_live_..."Best Practices
- Verify signatures — Always validate HMAC-SHA256
- Be idempotent — Same event may be delivered multiple times
- Respond quickly — Keep handler under 30 seconds
- Queue async work — Use a job queue for slow operations
- Log deliveries — Store webhook data for debugging
- Monitor health — Alert if webhooks fail repeatedly
- Use HTTPS — Required for security
- 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