Event types
| Event | When it fires | Payload type | Use case |
|---|---|---|---|
leaf_admitted |
Governance Envelope admitted to log | AGTS_GOVERNANCE_ENVELOPE_V1 |
Trigger downstream workflows on successful governance |
gate_fail |
One or more gates rejected evidence | Gate failure summary with gates_failed |
Trigger alert, block deployment, escalate to review |
compliance_report_ready |
Compliance report generated for a proof bundle | AGTS_COMPLIANCE_REPORT_V1 |
Notify compliance officer; push to document management system |
execution_trace_admitted |
Execution trace leaf admitted (L2+) | AGTS_EXECUTION_TRACE_V1 |
Begin variance computation; update monitoring dashboard |
variance_recorded |
Variance record leaf admitted (L2+) | AGTS_VARIANCE_RECORD_V1 |
Update risk dashboard; compare against thresholds |
governance_breach |
Variance record with classification: "BREACH" or omega_breach: true |
Variance record + auth context | Immediate alert: governance gap detected — execution exceeded authorized bounds |
chain_depth_milestone |
Governance chain depth hits a milestone (10 / 100 / 1000 leaves) | Chain depth summary | Progress notification; update compliance dashboard |
observables_alert |
HCE observables cross a policy threshold | Observable summary + threshold crossed | Risk alert: system health or coherence degrading — review governance posture |
Registering a webhook
curl -X POST https://api.obligationsign.com/webhooks \
-H "Authorization: Bearer agts_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-system.example.com/governance-hook",
"events": ["leaf_admitted", "gate_fail", "governance_breach"],
"secret": "optional-signing-secret-you-generate"
}'
# Response:
{
"webhook_id": "wh_a7f3c2...",
"url": "https://your-system.example.com/governance-hook",
"events": ["leaf_admitted", "gate_fail", "governance_breach"],
"created_at": "2026-03-14T14:00:00Z"
}
Signature verification
Every delivery includes an X-AGTS-Signature-256 header. Verify it before processing:
// Node.js / Express
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-agts-signature-256'];
if (!signature) return false;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(req.rawBody) // must be raw bytes, not parsed JSON
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
app.post('/governance-hook', (req, res) => {
if (!verifyWebhook(req, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
// handle event.type:
switch (event.type) {
case 'leaf_admitted':
console.log('Leaf admitted:', event.leaf_hash);
break;
case 'governance_breach':
alertOnCall(event.payload);
break;
case 'gate_fail':
blockDeployment(event.payload.gates_failed);
break;
}
res.sendStatus(200);
});
Payload examples
leaf_admitted
{
"type": "leaf_admitted",
"tenant_id": "tn_a7f3c2...",
"leaf_index": 42,
"leaf_hash": "8f3a1b...",
"admitted_at": "2026-03-14T14:30:00Z",
"subject_id": "customer-chatbot:v1.2",
"replay_url": "https://obligationsign.com/replay?leaf=8f3a1b..."
}
gate_fail
{
"type": "gate_fail",
"tenant_id": "tn_a7f3c2...",
"subject_id": "customer-chatbot:v1.3",
"gates_failed": ["G1"],
"details": {
"G1": "confidence_interval_lower (0.62) below threshold (0.70)"
},
"action": "ACTION_BLOCKED",
"failed_at": "2026-03-14T14:31:00Z"
}
governance_breach
{
"type": "governance_breach",
"tenant_id": "tn_a7f3c2...",
"auth_leaf_hash": "8f3a1b...",
"exec_leaf_hash": "9c4b2d...",
"variance_leaf_hash": "7a5e3f...",
"classification": "BREACH",
"l2_distance": 0.31,
"omega_breach": true,
"drift_direction": { "H": "degraded", "C": "degraded", "E": "degraded" },
"recorded_at": "2026-03-14T14:32:00Z"
}
Delivery semantics
| Property | Value |
|---|---|
| Delivery latency | ≤ 5 seconds after log admission |
| Retry policy | Exponential backoff: 5s, 30s, 2m, 10m, 30m (5 attempts) |
| Timeout per attempt | 10 seconds |
| Success criteria | Your endpoint returns HTTP 200 |
| Ordering guarantee | Best-effort in admission order; no strict ordering guarantee across event types |
| At-least-once delivery | Yes — handle idempotency using leaf_hash or event timestamp |
| Maximum payload size | 128 KB |