Decisions & Escalations
Decisions & Escalations¶
Query the immutable decision log and manage the human review queue.
GET /v1/enforce/decisions
List decisions with pagination and filtering by action_type or decision.
GET /v1/enforce/decisions/{decision_id}
Get a single decision with full details.
GET /v1/enforce/escalations
List pending escalations (actions awaiting human review).
POST /v1/enforce/escalations/{id}/resolve
Approve or reject an escalated action. Body: {"resolution": "approved"|"rejected"}. Immediately unblocks any SDK call polling this escalation.
GET /v1/enforce/escalations/{id}/status
Poll the resolution status of a pending escalation. Returns {"ok": true, "status": "pending"|"approved"|"rejected"}. Called automatically by the SDK's wait_for_escalation() method every escalation_poll_interval seconds.
Query Decisions¶
# Get all blocked decisions
blocked = requests.get(
"https://www.xybern.com/api/v1/enforce/decisions",
headers={"X-API-Key": API_KEY},
params={"decision": "block", "per_page": 20}
).json()
for d in blocked["decisions"]:
print(f"{d['decision_id']}: {d['action_type']} → {d['decision']} "
f"(trust: {d['trust_score']}, {d['latency_ms']}ms)")
# Resolve an escalation
requests.post(
f"https://www.xybern.com/api/v1/enforce/escalations/{esc_id}/resolve",
headers={"X-API-Key": API_KEY},
json={"resolution": "approved", "reason": "Reviewed and safe to proceed"}
)
Stats Endpoint¶
GET /v1/enforce/stats
Aggregate enforcement statistics: decisions, block rate, avg latency, agent counts.
Plain-language explanations¶
Every decision carries two accounts of why it was made. The technical reasoning is what the engine recorded (metadata.amount > 50000 (actual 143000) (rule 'Mandate · …')); it is what the receipt and the offline verifier use, and it never changes. The explanation is the same facts written for a person:
The agent tried to settle a motor claim for SAR 143,000 based on a workshop estimate that matched the damage report. This was held for a person because the amount exceeds the SAR 50,000 limit for automatic settlement, so a human claims approver must review it.
The explanation is produced in two layers. A deterministic rewrite runs on every decision (instant, no model, works offline) and names the mandate by its full outcome text. When a model is configured, the record dialog asks for a polished version, which is cached on the decision so each decision costs one model call at most. The dialog shows the explanation with the technical reasoning under Technical detail; escalation cards show the agent's own stated reason (sent by the SDK as agent_reasoning) together with the reason the action was held.
Returns text, source (model or rules) and model. lang=ar produces the explanation in Arabic. Settings: XYBERN_EXPLAIN_MODEL (default deepseek-chat on Cloud; any model the deployment's provider serves), XYBERN_EXPLAIN=0 to disable the model layer and keep the deterministic text. The explanation is descriptive only: it is generated from the recorded facts and can never alter the decision, the receipt or the vault entry.