Webhooks
Webhooks
GOVERN Webhooks deliver real-time push notifications to your systems the moment a governance event occurs. Instead of polling the API for new findings, you register an endpoint and GOVERN delivers the event payload directly.
Webhooks are available on Professional, Federal, and Embedded tiers.
Setup and Configuration
Register a Webhook Endpoint
curl -X POST https://api.govern.archetypal.ai/v1/webhooks \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-service.example.com/govern/events", "events": [ "finding.created", "assessment.complete", "policy.violated", "drift.detected" ], "description": "Primary governance event sink", "active": true }'Response:
{ "id": "wh_01HXXXXXXXXXXX", "url": "https://your-service.example.com/govern/events", "events": ["finding.created", "assessment.complete", "policy.violated", "drift.detected"], "signing_secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "active": true, "created_at": "2026-04-12T14:00:00Z"}Store the signing_secret securely — it is shown only once and is used to verify all incoming payloads.
List Registered Webhooks
curl https://api.govern.archetypal.ai/v1/webhooks \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx"Delete a Webhook
curl -X DELETE https://api.govern.archetypal.ai/v1/webhooks/wh_01HXXXXXXXXXXX \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx"Update a Webhook
curl -X PATCH https://api.govern.archetypal.ai/v1/webhooks/wh_01HXXXXXXXXXXX \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "events": ["finding.created", "assessment.complete", "policy.violated", "drift.detected", "probe.disconnected"], "active": true }'Event Types
| Event | Trigger | Severity |
|---|---|---|
finding.created | A new governance finding is generated by Assess or Probe | Varies by finding |
assessment.complete | An assessment run finishes (pass, conditional, or fail) | Info |
policy.violated | A policy rule in Block or Warn mode triggers | HIGH or CRITICAL |
drift.detected | Energy detects behavioral deviation from baseline | MEDIUM–HIGH |
probe.disconnected | A Probe loses telemetry contact for more than 5 minutes | HIGH |
system.registered | A new AI system is registered in GOVERN (including shadow AI discovered by Energy) | Info |
finding.created
Fires when Assess or Probe generates a new governance finding. Includes the full finding record.
{ "event": "finding.created", "timestamp": "2026-04-12T14:23:17Z", "severity": "HIGH", "system_id": "sys_01HXXXXXXXXXXX", "details": { "finding_id": "fnd_01HXXXXXXXXXXX", "title": "No documented bias testing methodology", "description": "NIST AI RMF GOVERN-1.2 requires documented bias testing prior to deployment. No evidence found.", "control": "NIST_AI_RMF:GOVERN-1.2", "framework": "nist_ai_rmf", "system_name": "Hiring Decision Engine", "assessment_id": "asmnt_01HXXXXXXXXXXX", "remediation_id": "rem_01HXXXXXXXXXXX" }}assessment.complete
Fires when an assessment finishes. Includes the final verdict and score.
{ "event": "assessment.complete", "timestamp": "2026-04-12T15:00:00Z", "severity": "INFO", "system_id": "sys_01HXXXXXXXXXXX", "details": { "assessment_id": "asmnt_01HXXXXXXXXXXX", "verdict": "CONDITIONAL", "score": 0.74, "findings_count": 3, "high_findings": 1, "medium_findings": 2, "framework": "nist_800_53", "report_url": "https://govern.archetypal.ai/reports/asmnt_01HXXXXXXXXXXX" }}policy.violated
Fires when a governed AI system violates an active policy in Block or Warn enforcement mode.
{ "event": "policy.violated", "timestamp": "2026-04-12T16:45:00Z", "severity": "CRITICAL", "system_id": "sys_01HXXXXXXXXXXX", "details": { "violation_id": "vio_01HXXXXXXXXXXX", "policy_id": "pol_01HXXXXXXXXXXX", "policy_name": "No PII in model outputs", "enforcement_mode": "BLOCK", "action_taken": "blocked", "probe_id": "prb_01HXXXXXXXXXXX", "input_hash": "sha256:abc123...", "context": "Output contained pattern matching SSN format" }}drift.detected
Fires when Energy detects that a monitored AI system’s behavior has deviated from its established baseline.
{ "event": "drift.detected", "timestamp": "2026-04-12T17:10:00Z", "severity": "HIGH", "system_id": "sys_01HXXXXXXXXXXX", "details": { "drift_id": "dft_01HXXXXXXXXXXX", "system_name": "Customer Support Classifier", "drift_score": 0.72, "baseline_score": 0.91, "delta": -0.19, "detection_layer": "L2", "description": "Behavioral coherence dropped 19 points below baseline over 48-hour window", "recommended_action": "Trigger full Assess — compare against previous passing assessment" }}probe.disconnected
Fires when a Probe stops sending telemetry. Could indicate network issues, a restart, or unauthorized removal.
{ "event": "probe.disconnected", "timestamp": "2026-04-12T18:00:00Z", "severity": "HIGH", "system_id": "sys_01HXXXXXXXXXXX", "details": { "probe_id": "prb_01HXXXXXXXXXXX", "probe_name": "prod-hiring-engine-probe", "last_seen_at": "2026-04-12T17:55:00Z", "silence_duration_seconds": 300, "environment": "production" }}system.registered
Fires when a new AI system is registered — either by an admin through the Dashboard or automatically when Energy’s shadow AI detection discovers an undeclared system.
{ "event": "system.registered", "timestamp": "2026-04-12T09:00:00Z", "severity": "INFO", "system_id": "sys_01HXXXXXXXXXXX", "details": { "system_name": "Undeclared Inference Server", "registration_source": "energy_discovery", "discovery_method": "L1_ebpf_fingerprint", "host": "10.0.1.45", "runtime": "vLLM", "declared": false }}Payload Format
All webhook payloads share the same top-level structure:
{ "event": "<event_type>", "timestamp": "<ISO 8601 UTC timestamp>", "severity": "INFO | MEDIUM | HIGH | CRITICAL", "system_id": "<system identifier or null for org-level events>", "details": { // Event-specific fields — see per-event docs above }}HTTP delivery headers:
POST /your/endpoint HTTP/1.1Content-Type: application/jsonX-Govern-Event: finding.createdX-Govern-Signature-256: sha256=<hmac_hex_digest>X-Govern-Delivery: <unique delivery UUID>X-Govern-Hook-ID: wh_01HXXXXXXXXXXXUser-Agent: Govern-Hookbot/1.0Webhook Signature Verification
Every payload is signed using HMAC-SHA256 with your webhook’s signing_secret. Always verify signatures before processing payloads. This prevents replay attacks and ensures the payload originated from GOVERN.
Verification Algorithm
- Extract the raw request body as bytes (do not parse JSON first).
- Extract the
X-Govern-Signature-256header value — format issha256=<hex_digest>. - Compute
HMAC-SHA256(signing_secret, raw_body). - Compare the computed digest to the header value using a constant-time comparison.
Python Example
import hmacimport hashlibfrom flask import Flask, request, abort
app = Flask(__name__)SIGNING_SECRET = "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
@app.route("/govern/events", methods=["POST"])def receive_govern_event(): # 1. Get raw body before any parsing payload = request.get_data()
# 2. Extract signature header sig_header = request.headers.get("X-Govern-Signature-256", "") if not sig_header.startswith("sha256="): abort(400, "Missing signature")
expected_sig = sig_header[len("sha256="):]
# 3. Compute HMAC computed_sig = hmac.new( SIGNING_SECRET.encode("utf-8"), payload, hashlib.sha256 ).hexdigest()
# 4. Constant-time comparison if not hmac.compare_digest(computed_sig, expected_sig): abort(403, "Invalid signature")
# Safe to process event = request.get_json() handle_event(event) return "", 200Node.js / TypeScript Example
import crypto from "crypto";import express from "express";
const SIGNING_SECRET = "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
app.post("/govern/events", express.raw({ type: "application/json" }), (req, res) => { const sigHeader = req.headers["x-govern-signature-256"] as string; if (!sigHeader?.startsWith("sha256=")) { return res.status(400).send("Missing signature"); }
const expectedSig = sigHeader.slice("sha256=".length); const computedSig = crypto .createHmac("sha256", SIGNING_SECRET) .update(req.body) .digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(computedSig), Buffer.from(expectedSig))) { return res.status(403).send("Invalid signature"); }
const event = JSON.parse(req.body.toString()); handleEvent(event); res.status(200).send();});Retry Policy
If your endpoint returns a non-2xx HTTP status code or does not respond within 30 seconds, GOVERN retries the delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 (initial) | Immediate |
| 2 | 30 seconds |
| 3 | 5 minutes |
After 3 failed attempts, the delivery is marked as failed. Failed deliveries are visible in the Dashboard under Settings → Webhooks → Delivery Log.
Best practices for reliable delivery:
- Return a 200 response immediately upon receipt, then process asynchronously.
- Use a durable queue (SQS, Pub/Sub, RabbitMQ) as your webhook receiver.
- Idempotency: use the
X-Govern-Deliveryheader as your deduplication key — GOVERN may deliver the same event more than once in retry scenarios.
Testing Webhooks
Dry-Run Mode
Send a test delivery to your endpoint using the GOVERN Dashboard or API without waiting for a real event to occur.
Via Dashboard: Settings → Webhooks → select your webhook → “Send Test Event”
Via API:
curl -X POST https://api.govern.archetypal.ai/v1/webhooks/wh_01HXXXXXXXXXXX/test \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "event": "finding.created" }'The test delivery sends a realistic sample payload (not real org data) to your registered endpoint. The delivery is signed with your real signing secret, so your verification logic is exercised end-to-end.
Local Development
For local testing, use a tunneling tool to expose your local server:
# Using ngrokngrok http 3000
# Register the tunnel URL as your webhook endpointcurl -X POST https://api.govern.archetypal.ai/v1/webhooks \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://abc123.ngrok.io/govern/events", "events": ["finding.created", "assessment.complete"] }'Delivery Log
All delivery attempts — successful and failed — are logged and visible for 30 days:
curl https://api.govern.archetypal.ai/v1/webhooks/wh_01HXXXXXXXXXXX/deliveries \ -H "Authorization: Bearer gvn_live_xxxxxxxxxxxx"The delivery log shows: delivery ID, event type, HTTP status returned by your endpoint, response time, and whether the delivery succeeded or exhausted retries.