Outbound Webhooks¶
agentgovernance.dev supports outbound webhooks — real-time HTTP callbacks that fire when behavioral pattern detections occur during observation analysis.
Webhooks enable external systems to receive governance signals as they happen, supporting human-in-the-loop intervention workflows, alerting pipelines, and audit integrations.
How It Works¶
- Register a webhook endpoint via the API.
- A one-time signing secret is returned (save it — it is never shown again).
- When
POST /api/v1/observe/assessdetects a P1 or P2 pattern, the engine fires an HTTP POST to every active webhook registered for that organization. - Each delivery is signed with HMAC-SHA256 so the receiver can verify authenticity.
Severity Filtering¶
| Severity | Default Behavior |
|---|---|
| P1 | Always fires |
| P2 | Fires if included in the webhook's events config (default: yes) |
| P3 | Never fires via webhook |
| ADV | Never fires via webhook |
API Reference¶
All webhook endpoints require Bearer token authentication (your organization API key).
Register a Webhook¶
POST /api/v1/webhooks
Authorization: Bearer <api-key>
Content-Type: application/json
{
"url": "https://your-system.example.com/webhook/governance",
"events": ["P1", "P2"],
"description": "Production alerting endpoint"
}
Response (201 Created):
{
"webhookId": "a1b2c3d4-...",
"url": "https://your-system.example.com/webhook/governance",
"events": ["P1", "P2"],
"secret": "whsec_abc123...",
"createdAt": "2026-03-17T20:00:00.000Z"
}
Save the secret
The secret is returned once at registration. Store it securely — it is
required to verify webhook signatures on your end.
List Webhooks¶
Returns all registered webhooks for the organization. The secret field is
never included in list responses.
Delete a Webhook¶
Permanently removes a webhook registration. Deliveries in-flight may still complete.
Webhook Payload¶
When a P1 or P2 pattern is detected, each matching webhook receives an HTTP POST with the following JSON body:
{
"event": "pattern.detected",
"observationId": "uuid",
"timestamp": "2026-03-17T20:05:00.000Z",
"agentId": "uuid | null",
"runId": "uuid | null",
"currentGate": "plan | build | review_eng | ... | null",
"pattern": {
"id": "BP-004",
"name": "Scope Creep",
"severity": "P2",
"category": "Scope violation",
"reasoning": "Agent adds work that was not part of the original work order.",
"governanceResponse": "PAUSE"
},
"detection": {
"confidence": 0.85,
"layer": "regex",
"matchCount": 3
}
}
Field Reference¶
| Field | Type | Description |
|---|---|---|
event |
string | Always "pattern.detected" |
observationId |
UUID | ID of the stored behavioral observation |
timestamp |
ISO 8601 | UTC time of detection |
agentId |
UUID or null | Agent ID if provided in the assess call |
runId |
UUID or null | Governance run ID if provided |
currentGate |
string or null | Current phase gate of the run (looked up from governanceRuns) |
pattern.id |
string | Pattern identifier (e.g., BP-001) |
pattern.name |
string | Human-readable pattern name |
pattern.severity |
string | P1 or P2 |
pattern.category |
string | Pattern category from the taxonomy |
pattern.reasoning |
string | Description of why this pattern is significant |
pattern.governanceResponse |
string | Recommended response (HALT, PAUSE, etc.) |
detection.confidence |
float | Detection confidence score (0–1) |
detection.layer |
string | Detection method (currently regex) |
detection.matchCount |
integer | Number of regex matches found |
Privacy
Raw regex match strings are not included in webhook payloads. Matched text remains server-side in the observation record.
Signature Verification¶
Every webhook delivery includes two headers for signature verification:
| Header | Value |
|---|---|
X-AG-Signature |
sha256=<hex-encoded HMAC> |
X-AG-Timestamp |
Unix timestamp (seconds) |
Verification Algorithm¶
The signature is computed as:
Example (Node.js)¶
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-ag-signature'];
const timestamp = req.headers['x-ag-timestamp'];
const body = JSON.stringify(req.body);
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Example (Python)¶
import hmac
import hashlib
def verify_webhook(headers, body, secret):
signature = headers.get('X-AG-Signature', '')
timestamp = headers.get('X-AG-Timestamp', '')
expected = 'sha256=' + hmac.new(
secret.encode(),
f'{timestamp}.{body}'.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
Delivery Behavior¶
Retry Policy¶
If the receiving endpoint returns a non-2xx status or the request times out, the engine retries with the following schedule:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 5 seconds |
| 3 | 30 seconds |
Each attempt has a 5-second timeout. After 3 failed attempts, the delivery
is abandoned and a webhook_delivery_failed event is recorded in the
organization's audit trail.
Non-Blocking¶
Webhook dispatch runs concurrently with the API response. The
POST /api/v1/observe/assess response is never delayed by webhook delivery.
Integration Example¶
A complete integration flow:
# 1. Register your organization
curl -X POST https://agentgovernance.dev/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"name": "Acme Corp", "slug": "acme"}'
# → Save the API key
# 2. Register a webhook
curl -X POST https://agentgovernance.dev/api/v1/webhooks \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-system.example.com/governance-alerts"}'
# → Save the webhook secret
# 3. Submit text for analysis — webhook fires on detection
curl -X POST https://agentgovernance.dev/api/v1/observe/assess \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{"text": "I will handle this myself without approval"}'
# → If P1/P2 detected, your endpoint receives the webhook
Audit Trail¶
All webhook lifecycle events are recorded in the organization's audit trail:
| Action | Description |
|---|---|
created |
Webhook endpoint registered |
deleted |
Webhook endpoint removed |
webhook_delivery_failed |
All retry attempts exhausted for a delivery |
Query the audit trail to review webhook activity: