api reference
Intended Documentation
API Reference: Intents
Submit an IntentRequest to the authority runtime and get an APPROVED, ESCALATED, or DENIED decision with a single-use Ed25519 token. Full request/response contract, status codes, and error modes.
Intents API#
POST /intent is the core of the runtime. You submit an IntentRequest — who wants to do what, to which system, with what risk context — and the route runs the full authority loop in one round trip: it evaluates policy, computes a risk score, reaches a decision, mints a single-use Ed25519 token only if the action is approved, attempts execution through the bound adapter, and appends every step to the per-tenant SHA-256 audit chain.
The decision is one of three legacy-enum outcomes, each with its own HTTP status:
| Decision | HTTP | Token minted? | Meaning |
|---|---|---|---|
APPROVED | 200 | Yes (EdDSA) | Policy passed and execution succeeded. |
ESCALATED | 202 | No (null) | A human approval is required; an escalation/approval request was opened. |
DENIED | 403 | No (null) | Fail-closed deny. No token, no execution. |
Warning
These are the only values /intent returns. The modern POST /authority/evaluate engine uses a different vocabulary (ALLOW / DENY / REQUIRE_APPROVAL / ESCALATE) — see the Policies API. Do not mix them in one client.
A single POST /intent request runs the entire loop and returns the decision, token, execution result, and audit head together.
Submit an Intent#
riskContext fields#
| Field | Type | Required | Notes |
|---|---|---|---|
baseRiskScore | integer 0–100 | yes | Starting risk before modifiers. |
policyCompliant | boolean | yes | Caller's own compliance assertion. |
requiresPrivilegedAccess | boolean | no (default false) | Adds +20 to risk when true. |
touchesProduction | boolean | no (default false) | Adds +20 to risk when true. |
containsSensitiveData | boolean | no (default false) | Adds +15 to risk when true. |
justification | string | no | Free-text rationale, carried into the record. |
github | object | yes | Workflow target: { owner, repo, ref, workflowId?, inputs?, pullRequest? }. |
The final risk score is baseRiskScore + (privileged?20) + (production?20) + (sensitive?15), capped at 100. The modifier weights (20/20/15) are tenant-overridable defaults.
Info
targetSystem is cross-validated: it must equal riskContext.github.owner + "/" + riskContext.github.repo. A mismatch returns 400 VALIDATION_ERROR with the offending path. The request body is strict — unknown top-level fields are rejected.
Request#
Response fields#
| Field | Type | Notes |
|---|---|---|
intentId | string (uuid) | The persisted intent's id. |
correlationId | string (uuid) | Ties together every audit entry for this request. |
authorityDecision | object | { decision, riskScore, policyCompliant, rationale[], gateTrace[] }. |
authorityDecisionToken | string | null | Ed25519 JWT on APPROVED; null on ESCALATED / DENIED. |
execution | object | { attempted, status, adapterId?, reason? }. status is executed / skipped / failure. |
audit | object | { entriesWritten, latestHash } — count of entries appended and the new chain head. |
escalationId | string | Escalate only. The opened escalation record id. |
approvalRequestId | string | null | Escalate only. The approval request id, or null. |
explanation / summary | object / string | Human-readable rendering of the decision rationale. |
The nested authorityDecision.gateTrace[] is an ordered list of { gate, outcome: "PASSED"|"FAILED"|"SKIPPED", reason } entries — the recorded path the loop took to its decision.
Response — Approved (200)#
Response — Escalated (202)#
Response — Denied (403)#
About the token#
When the decision is APPROVED, authorityDecisionToken is an Ed25519 JWT signed with a per-tenant key (header carries alg: "EdDSA", kid). Its TTL defaults to and is capped at 300 seconds, and its nonce is single-use — the bound adapter consumes it atomically, so a replayed token is rejected. An adapter validates the token before it runs anything (kid pinning, tenant/adapter binding, decision === "APPROVED", expiry, nonce consume). See Decision Token Model.
Failure modes#
| Status | Code | Cause | Notes |
|---|---|---|---|
400 | VALIDATION_ERROR | Body failed schema (e.g. targetSystem ≠ owner/repo, unknown field) | issues[] carries the Zod paths. |
401 | UNAUTHORIZED / INVALID_PORTAL_SESSION | Missing/invalid credential | See Authentication. |
403 | TENANT_MISMATCH | Body tenantId ≠ credential tenant | Cross-tenant boundary. |
403 | (denied decision) | DENIED outcome | This is a decision, not an auth error — body carries the full authorityDecision. |
403 | (approved but blocked) | Execution blocked despite approval | execution.status !== "executed" returns 403 with the token still present. |
429 | RATE_LIMITED | Per-IP rate limit exceeded | Back off and retry. |
500 | AUTHORITY_LOOP_FAILED | Any uncaught failure in the loop | Fail-closed — treat as a deny. |
List Intents#
Response: { tenantId, total, limit, offset, intents: [...] }.
Get Intent Detail#
Simulate Without Persistence#
The response is explicit about being a dry run:
Next steps#
- Authentication — credential types and the auth gate
- Policies API — the rules that drive these decisions
- Decision Token Model — token claims and verification
- Audit API — pull the chain these calls write to