API reference
This page is rendered at build time from the machine-readable contract, contract/openapi.json (OpenAPI 3.1). That file is generated from the API's own zod request schemas by packages/agent-skill/scripts/build-contract.ts, and a test (packages/agent-skill/test/contract.test.ts) fails if the committed contract drifts from the code.
It covers the agent-facing action contract (the three base operations submit, status and resume, plus cancel, receipt and delegation), the provider interface used by the embedded SDK, the policy simulator, and the reconciliation lookup that a provider implements. Console, Control and public service endpoints are listed in the Control API. Errors use the codes in Errors and reason codes.
Two behaviours the schema cannot express:
POST /v1/actionsanswers202whenever the action ispending_approvalorapproved, including a replay of an existing pending action with the same operation key.200is a replay of an action in any other state;201is a newly created action that completed or closed synchronously (including a recorded denial).- An action ID alone never proves permission: status, resume, cancel and receipt return
404to any agent other than the original one.
Authentication schemes
| Scheme | HTTP scheme | Description |
|---|---|---|
dpop | DPoP | Authorization: DPoP <token> plus a DPoP header proof bound to method, URL and token hash (ath) on every request |
projectApiKey | bearer | Project API key (axk_…) with provider:authorize |
Headers
| Header | Meaning |
|---|---|
Idempotency-Key | Operation key, forwarded to upstreams on dispatch |
Axiom-Action-Id | Action ID, forwarded to upstreams |
Axiom-Root-Action-Id | Root action ID for delegated child operations |
Axiom-Authorization | Compact JWS (typ axiom-dispatch+jws, grant key) stating exactly what was authorised |
axiom-outcome | Provider response header: compact JWS (typ axiom-outcome+jws) of axiom.outcome.v1 |
Agent operations
Called by the agent with a DPoP-bound access token
POST/oauth/token
client_credentials with private_key_jwt (RFC 7523) and a DPoP proof (RFC 9449)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
DPoP | header | string | yes | Proof with htm=POST, htu=token endpoint |
Request body
Responses
| Status | Description | Body |
|---|---|---|
200 | DPoP-bound access token (5 minutes) | TokenResponse |
400 | OAuth error (RFC 6749 §5.2) | |
401 | invalid_client or invalid_dpop_proof |
POST/v1/actions
Submit an action; returns its durable ID and state
Request body
Responses
| Status | Description | Body |
|---|---|---|
200 | Replay of an existing action with the same operation key and request | ActionStatus |
201 | Created and completed (or closed) synchronously | ActionStatus |
202 | pending_approval or approved: persist the ID and wait | ActionStatus |
403 | Denied before an action was created (e.g. tenant_mismatch) | Problem |
409 | idempotency_conflict: same operation key, different material request; see changed_fields | Problem |
422 | validation_failed | Problem |
GET/v1/actions/{action_id}
Authenticated status read (the only source of truth)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
action_id | path | string | yes |
Responses
| Status | Description | Body |
|---|---|---|
200 | Current status | ActionStatus |
404 | Not found, or not visible to this caller | Problem |
POST/v1/actions/{action_id}/resume
Resume an approved action as the original agent with the approved params
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
action_id | path | string | yes |
Request body
Responses
| Status | Description | Body |
|---|---|---|
200 | Final or closed state | ActionStatus |
202 | executing: track by status reads only | ActionStatus |
403 | wrong_resume_actor or a policy recheck failed | Problem |
409 | invalid_state (not yet approved; honour retry_after_seconds) or conflict (params differ from the approval) | Problem |
POST/v1/actions/{action_id}/cancel
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
action_id | path | string | yes |
Responses
| Status | Description | Body |
|---|---|---|
200 | Cancelled (or already closed) | ActionStatus |
GET/v1/actions/{action_id}/receipt
Signed receipt bundle; verify offline with the embedded key snapshot
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
action_id | path | string | yes | |
reveal | query | string | no | Comma-separated fields to disclose |
Responses
| Status | Description | Body |
|---|---|---|
200 | Receipt bundle | ReceiptBundle |
404 | Not found | Problem |
POST/v1/grants/{grant_id}/delegate
Explicit delegation: a narrower child grant for another agent, bound to one root action
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grant_id | path | string | yes |
Request body
Responses
| Status | Description | Body |
|---|---|---|
201 | Child grant | DelegationResult |
403 | Delegation not permitted | Problem |
Provider operations
Called by the receiving application with a project API key (embedded SDK)
POST/v1/actions/{action_id}/outcome
Embedded SDK: report the provider-signed axiom.outcome.v1 attestation
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
action_id | path | string | yes |
Request body
Responses
| Status | Description | Body |
|---|---|---|
200 | Closed with the attested outcome | ActionStatus |
403 | Attestation rejected | Problem |
POST/v1/projects/{project_id}/simulate
Policy simulator: expected allow / deny / approval with the rule trace; creates nothing
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
project_id | path | string | yes |
Request body
Responses
| Status | Description | Body |
|---|---|---|
200 | Decision and trace |
Provider-implemented operations
Implemented by the receiving application; called by Axiom
GET/.well-known/axiom/operations/{operation_key}
Reconciliation lookup Axiom calls on the provider after an unknown outcome
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
operation_key | path | string | yes | |
Axiom-Authorization | header | string | yes | axiom.dispatch.v1 JWS for the same operation key |
Responses
| Status | Description | Body |
|---|---|---|
200 | Committed result | object |
404 | The operation key never committed |
Discovery operations
GET/v1/capabilities
Supported wait modes, warm-wait bound, retry interval and endpoints
Responses
| Status | Description | Body |
|---|---|---|
200 | Capabilities | Capabilities |
GET/.well-known/jwks.json
Every Axiom signing key ever used, annotated with axiom:role and axiom:status
Responses
| Status | Description | Body |
|---|---|---|
200 | JWK set |
Webhooks (called by Axiom)
POSTwakeEvent
Signed, data-minimised wake event. Verify with the issuer JWKS (role event), drop seq <= last processed, then read status.
Schemas
The same schemas are published individually as JSON Schema 2020-12 documents under /contract/schemas/.
SubmitActionRequest
Submit an action
| Field | Type | Required | Notes |
|---|---|---|---|
operation_key | string | yes | Client-provided idempotency key, stable across retries. min length 8, max length 200 |
operation | string | yes | min length 1, max length 128 |
service | string | yes | min length 1 |
tenant | string | yes | min length 1 |
resource | object | yes | |
params | map of Json | yes | |
not_after | string (date-time) | no | |
parent_action_id | string | no | |
intent | string | no | max length 500 |
payload | map of Json | no | |
execute | boolean | no | default true |
ResumeActionRequest
Resume an approved action as the original agent
| Field | Type | Required | Notes |
|---|---|---|---|
operation_key | string | yes | min length 8, max length 200 |
resource | object | yes | |
params | map of Json | yes | |
payload | map of Json | no |
DelegateRequest
| Field | Type | Required | Notes |
|---|---|---|---|
child_agent | string | yes | |
root_action_id | string | yes | |
operations | string[] | yes | |
resources | object[] | yes | |
expires_at | string (date-time) | yes |
AuthorizeRequest
| Field | Type | Required | Notes |
|---|---|---|---|
agent | object | yes | |
action | object | yes |
OutcomeRequest
| Field | Type | Required | Notes |
|---|---|---|---|
attestation | string | yes | Compact JWS of an axiom.outcome.v1 document signed by a registered provider key |
SimulateRequest
| Field | Type | Required | Notes |
|---|---|---|---|
service_id | string | yes | |
operation | string | yes | |
tenant_id | string | yes | |
agent_id | string | no | |
grant_id | string | no | |
resource | object | yes | |
params | map of any | yes | |
environment | string | no | |
candidate | object | no |
ActionStatus
Authoritative action status
| Field | Type | Required | Notes |
|---|---|---|---|
action_id | string | yes | |
root_action_id | string | yes | |
parent_action_id | string | no | |
state | ActionState | yes | |
reason_code | ReasonCode | yes | |
progress | "delivery_pending" | "waiting_on_person" | "decision_readback_unavailable" | "awaiting_agent_resume" | "reconciling" | no | |
operation | string | yes | |
operation_key | string | yes | |
tenant | string | yes | |
service | string | yes | |
grant_id | string | no | |
request_digest | string | yes | sha-256 digest of the canonical action the approver saw |
summary | string | yes | |
status_url | string | yes | |
resume_url | string | yes | |
receipt_url | string | no | |
decision_deadline | string | no | Deadline to receive a verified decision |
resume_deadline | string | no | Last time to resume an approved action |
expires_at | string | no | RFC 3339 timestamp |
retry_after_seconds | integer | no | Poll no sooner than this. ≥ 0, ≤ 9007199254740991 |
supported_modes | "poll" | "webhook" | "mcp_task" | "sse"[] | yes | |
resume_actor | "original_agent" | yes | |
approvals | object[] | no | |
outcome | object | no | |
created_at | string | yes | RFC 3339 timestamp |
updated_at | string | yes | RFC 3339 timestamp |
ActionState
Action lifecycle state (brief §5 state table)
"pending_approval" | "approved" | "executing" | "succeeded" | "failed" | "outcome_unknown" | "denied" | "expired" | "revoked" | "cancelled"
ReasonCode
Why the action is in its state
"allowed_by_grant" | "approval_required" | "finance_approval_required" | "second_approver_required" | "awaiting_delivery" | "awaiting_decision" | "decision_readback_unavailable" | "awaiting_agent_resume" | "no_grant" | "grant_expired" | "grant_revoked" | "grant_scope_mismatch" | "tenant_mismatch" | "audience_mismatch" | "resource_not_permitted" | "operation_not_permitted" | "agent_suspended" | "agent_retired" | "credential_revoked" | "issuer_not_trusted" | "ceiling_exceeded" | "policy_deny" | "emergency_deny" | "delegation_not_permitted" | "delegation_expands_scope" | "delegation_depth_exceeded" | "wrong_resume_actor" | "material_change" | "approval_denied" | "approval_expired" | "approver_ineligible" | "separation_of_duties" | "policy_stale" | "status_stale" | "quota_exceeded" | "invalid_request" | "dispatched" | "target_confirmed" | "target_failed" | "target_timeout" | "gateway_observed_success" | "gateway_observed_failure" | "resume_expired" | "reconciled" | "cancelled_by_requester"
Problem
RFC 9457 problem details
| Field | Type | Required | Notes |
|---|---|---|---|
type | string | yes | |
title | string | yes | |
status | integer | yes | ≥ -9007199254740991, ≤ 9007199254740991 |
code | "unauthenticated" | "invalid_token" | "invalid_dpop_proof" | "forbidden" | "not_found" | "conflict" | "idempotency_conflict" | "invalid_state" | "precondition_failed" | "invalid_request" | "validation_failed" | "rate_limited" | "quota_exceeded" | "upstream_error" | "upstream_timeout" | "internal" | yes | |
detail | string | no | |
reason_code | ReasonCode | no | |
changed_fields | string[] | no | Material fields that differ (idempotency conflicts) |
action_id | string | no | |
issues | object[] | no | |
retry_after_seconds | integer | no | ≥ -9007199254740991, ≤ 9007199254740991 |
Capabilities
Capability discovery: read before choosing how to wait
| Field | Type | Required | Notes |
|---|---|---|---|
api_version | "2026-11-14" | yes | |
issuer | string | yes | |
supported_modes | "poll" | "webhook" | "mcp_task" | "sse"[] | yes | |
mcp | object | yes | |
max_warm_wait_seconds | integer | yes | ≥ -9007199254740991, ≤ 9007199254740991 |
default_retry_after_seconds | integer | yes | ≥ -9007199254740991, ≤ 9007199254740991 |
resume_actor | "original_agent" | yes | |
jwks_uri | string | yes | |
token_endpoint | string | yes | |
receipt_format | "axiom.receipt.v1" | yes | |
canonical_format | "axiom.action.v1" | yes | |
delegation | object | yes |
WakeEvent
Payload of a signed wake event (compact JWS, typ axiom-event+jws). Never authority: read status after it.
| Field | Type | Required | Notes |
|---|---|---|---|
v | "axiom.event.v1" | yes | |
event_id | string | yes | |
type | "action.changed" | "agent.suspended" | "grant.revoked" | "policy.updated" | yes | |
action_id | string | no | |
tenant | string | yes | |
occurred_at | string | yes | RFC 3339 timestamp |
seq | integer | yes | Monotonic per action; drop events with seq <= the last processed. ≥ -9007199254740991, ≤ 9007199254740991 |
ReceiptBundle
Signed receipt bundle (JWS general serialization + salted disclosures + key snapshot)
| Field | Type | Required | Notes |
|---|---|---|---|
type | "axiom.receipt.bundle.v1" | yes | |
receipt | object | yes | |
disclosures | map of object | yes | |
keys | object[] | yes | |
status | object | no |
TokenResponse
OAuth token response for agents (client_credentials + private_key_jwt + DPoP)
| Field | Type | Required | Notes |
|---|---|---|---|
access_token | string | yes | |
token_type | "DPoP" | yes | |
expires_in | integer | yes | ≥ -9007199254740991, ≤ 9007199254740991 |
scope | string | yes |
DelegationResult
| Field | Type | Required | Notes |
|---|---|---|---|
grant_id | string | yes | |
parent_grant_id | string | yes | |
root_action_id | string | yes | |
agent | string | yes | |
operations | string[] | yes | |
resources | object[] | yes | |
expires_at | string | yes | |
depth | integer | yes | ≥ -9007199254740991, ≤ 9007199254740991 |
AuthorizeResponse
Embedded-SDK authorize result; execute only when decision is execute
| Field | Type | Required | Notes |
|---|---|---|---|
decision | "execute" | "completed" | "pending" | "in_progress" | "stop" | yes | |
status | ActionStatus | yes | |
claim | object | no |
Json
string | number | boolean | null | Json[] | map of Json