Skip to content

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

Terminal window
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

Terminal window
curl https://api.govern.archetypal.ai/v1/webhooks \
-H "Authorization: Bearer gvn_live_xxxxxxxxxxxx"

Delete a Webhook

Terminal window
curl -X DELETE https://api.govern.archetypal.ai/v1/webhooks/wh_01HXXXXXXXXXXX \
-H "Authorization: Bearer gvn_live_xxxxxxxxxxxx"

Update a Webhook

Terminal window
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

EventTriggerSeverity
finding.createdA new governance finding is generated by Assess or ProbeVaries by finding
assessment.completeAn assessment run finishes (pass, conditional, or fail)Info
policy.violatedA policy rule in Block or Warn mode triggersHIGH or CRITICAL
drift.detectedEnergy detects behavioral deviation from baselineMEDIUM–HIGH
probe.disconnectedA Probe loses telemetry contact for more than 5 minutesHIGH
system.registeredA 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.1
Content-Type: application/json
X-Govern-Event: finding.created
X-Govern-Signature-256: sha256=<hmac_hex_digest>
X-Govern-Delivery: <unique delivery UUID>
X-Govern-Hook-ID: wh_01HXXXXXXXXXXX
User-Agent: Govern-Hookbot/1.0

Webhook 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

  1. Extract the raw request body as bytes (do not parse JSON first).
  2. Extract the X-Govern-Signature-256 header value — format is sha256=<hex_digest>.
  3. Compute HMAC-SHA256(signing_secret, raw_body).
  4. Compare the computed digest to the header value using a constant-time comparison.

Python Example

import hmac
import hashlib
from 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 "", 200

Node.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:

AttemptDelay
1 (initial)Immediate
230 seconds
35 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-Delivery header 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:

Terminal window
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:

Terminal window
# Using ngrok
ngrok http 3000
# Register the tunnel URL as your 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://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:

Terminal window
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.