Decisions API
Endpoints for retrieving policy-decision context. Implements the contract in ADR-043.
All endpoints require Basic auth (CLIENT_ID:CLIENT_SECRET) or a valid JWT. See Auth header matrix.
GET /api/v1/decisions/{decision_id}/explain
Fetch the full explanation for a previously-made policy decision.
Authorization
- Caller must either own the decision (user_email match) or belong to the same tenant.
- Bounded by tier retention (see explainability).
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
decision_id | path | string | Global decision identifier returned in the original step gate / policy evaluation response. URL-encoded. |
Response (200)
{
"decision_id": "dec_wf123_step4",
"timestamp": "2026-04-17T12:00:00Z",
"decision": "deny",
"reason": "SQL injection patterns detected",
"risk_level": "high",
"policy_matches": [
{
"policy_id": "pol-sqli-detector",
"policy_name": "SQL Injection Detector",
"action": "deny",
"risk_level": "high",
"allow_override": true,
"policy_description": "Blocks SQL injection patterns"
}
],
"matched_rules": [
{
"policy_id": "pol-sqli-detector",
"rule_id": "sqli-union-select",
"rule_text": "Contains UNION SELECT keyword combination",
"matched_on": "query.sql"
}
],
"override_available": true,
"override_existing_id": "ov-f3a81c...",
"historical_hit_count_session": 3,
"policy_source_link": "https://policies.axonflow/sqli-detector",
"tool_signature": "Bash"
}
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
decision_id | string | yes | Echoes the path param. |
timestamp | ISO 8601 string | yes | When the decision was made. |
decision | string | yes | allow | deny | require_approval. |
reason | string | yes | Human-readable reason. May be empty for allow decisions. |
risk_level | string | no | low | medium | high | critical. |
policy_matches | array | yes | Policies that contributed to the decision. Can be empty for default-allow. |
matched_rules | array | no | Rule-level detail. Populated when the upstream engine supports it. |
override_available | bool | yes | True iff at least one matched policy has allow_override=true AND risk_level != critical. |
override_existing_id | string | no | ID of an already-active override for this caller/policy. |
historical_hit_count_session | int | yes | Times the same (policy, user) pair hit in the rolling 24h window. |
policy_source_link | string | no | URL to the policy definition. |
tool_signature | string | no | Scoped tool name, if the decision was tool-scoped. |
Error responses
| Status | Meaning |
|---|---|
| 400 | decision_id missing or malformed |
| 401 | Auth failure |
| 403 | Caller does not own the decision and is not in the same tenant |
| 404 | Decision not found or past tier retention window |
Example
curl -X GET https://your-platform/api/v1/decisions/dec_wf123_step4/explain \
-u "$CLIENT_ID:$CLIENT_SECRET"
Versioning
The response shape is frozen per ADR-043. Additive fields may appear in future minor versions with omitempty semantics — clients should tolerate unknown fields. Renames or removals require a major version bump.
See also
- Explainability concept
- Session Overrides — the next step when
override_available: true - Audit API —
decision_id,policy_name, andoverride_idfilters
