Webhook Events Catalog
Every Adjudon webhook delivery carries an event name in the
x-adjudon-event header and the same name on the body's event
field. This page is the catalog: every event currently dispatched,
with its full payload schema and a sample JSON. Subscribe to one
event by name, several events by listing them, or all events with
the * wildcard. Tested against API version v1.
Every delivery body wraps the event-specific payload in a fixed envelope:
{
"event": "<event-name>",
"timestamp": "2026-05-06T10:14:22.317Z",
"data": { /* event-specific payload, PII-scrubbed */ }
}
The data block is what changes per event. Every payload below is
the verbatim shape the dispatcher emits today.
Event summary
| Event | Subscribable | Fires when |
|---|---|---|
trace.created | yes | A DecisionTrace is created with a non-blocked, non-flagged status (the standard approve path) |
trace.blocked | wildcard only | A DecisionTrace ingestion is rejected by the Policy Engine (HTTP 403 ADJ_BLOCKED_BY_POLICY) |
trace.hold_for_review | wildcard only | A DecisionTrace is held for human review (HTTP 202) and a ReviewItem is created |
alert.triggered | yes | An alert rule matches a trace |
agent.created | yes | Roadmap — subscription enum exists; dispatch path not yet wired |
setting.updated | yes | Roadmap — subscription enum exists; dispatch path not yet wired |
The "Subscribable" column is the honesty column. The four events in
the model's events enum (trace.created, alert.triggered,
agent.created, setting.updated, plus *) are what a webhook can
register for at create time. The two trace.blocked and
trace.hold_for_review events are dispatched by the server today
but are not in the subscription enum yet, so they reach
subscribers only via a wildcard (*) subscription. This is
documented honestly so procurement and integration engineers do not
discover the asymmetry through silent missing deliveries.
trace.created
Fires after a successful trace ingestion (HTTP 201). Approved
decisions only; blocked and held decisions fire their own events.
{
"traceId": "trace_aBcD1234",
"agentName": "underwriter-v1",
"status": "approved",
"latency": 42,
"timestamp": "2026-05-06T10:14:22.317Z"
}
{
"event": "trace.created",
"timestamp": "2026-05-06T10:14:22.317Z",
"data": {
"traceId": "trace_aBcD1234",
"agentName": "underwriter-v1",
"status": "approved",
"latency": 42,
"timestamp": "2026-05-06T10:14:22.317Z"
}
}
latency is the millisecond round-trip recorded by the agent at
trace-call time. status is the DecisionTrace.status enum value;
approved is the typical value here.
trace.blocked
Fires when the Policy Engine returns block and the request gets a
403 ADJ_BLOCKED_BY_POLICY. Subscribable only via * today.
{
"traceId": "trace_aBcD1234",
"agentName": "underwriter-v1",
"status": "blocked",
"reason": "Policy 'Block low-confidence loan denials' matched",
"timestamp": "2026-05-06T10:14:22.317Z"
}
reason is the matched policy's stored reason text. Use this event
to fan out to incident-response channels — a blocked decision
is a moment your operator wants visibility on, not after the fact.
trace.hold_for_review
Fires when the Policy Engine returns flag_for_review, the response
is HTTP 202, and a ReviewItem is created. Subscribable only via
* today.
{
"traceId": "trace_aBcD1234",
"reviewId": "65b1f2c4d3e0a1b2c3d4e5f6",
"agentName": "underwriter-v1",
"timestamp": "2026-05-06T10:14:22.317Z"
}
The reviewId is the Mongo _id of the created ReviewItem.
Route this event to a Slack channel or PagerDuty rotation to bring
the human reviewer into the loop within the SLA your organisation
has set for human oversight under EU AI Act Article 14.
alert.triggered
Fires when an alert rule matches a trace. The dispatcher sends one event per matching rule, so a trace that triggers two rules produces two deliveries.
{
"ruleId": "65b1f2c4d3e0a1b2c3d4e5f6",
"ruleName": "Low-confidence finance decisions",
"traceId": "trace_aBcD1234",
"traceIdMongo": "65b1f2c4d3e0a1b2c3d4e5f7",
"condition": "confidenceScore < 0.7 AND tags includes 'finance'",
"valueTriggeredAt": 0.62
}
condition is the rule's stored condition string; valueTriggeredAt
is the value (typically a confidence score or a counter) that
crossed the threshold. Both fields are intended for triage UIs
that want to render the alert without re-querying the rule.
agent.created and setting.updated (roadmap)
Both events are accepted by the subscription enum but have no dispatch path wired today. A subscriber who creates a webhook listening for these events will not see any deliveries.
We document this honestly so integration engineers do not chase silent failures. When the dispatch paths ship, they will appear in the Changelog and the schema for each event will be added here. No "Coming soon" placeholder — if it is not in this catalog with a payload schema, it does not fire.
Subscribing
Subscribe to one event by name, several by listing them, or every
event with the * wildcard:
curl -X POST https://api.adjudon.com/api/v1/webhooks \
-H "Authorization: Bearer $ADJUDON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/adjudon",
"events": ["*"]
}'
The * subscription receives every event the server dispatches,
including the dispatch-only events listed above and any new events
that ship before they enter the subscription enum.
Versioning of payload shapes
Adjudon treats payload field-additions as backward-compatible: a
consumer that ignores unknown fields continues working when we add
a new field to an event's data. Field renames or removals require
a 90-day deprecation notice in the Changelog.
The wrapper envelope (event, timestamp, data) is stable until a
major API version bump.
See also
- Webhooks Overview — delivery shape, retry schedule, and SSRF guarantees
- Signature Verification — how to
verify the
x-adjudon-signatureheader in four languages - Webhook Config API — CRUD for managing webhooks
- Routing flagged decisions to Slack
— recipe for the
trace.hold_for_reviewandalert.triggeredfan-out