Checkpoints
A checkpoint asks for approval of a single agent action. You create one before the action runs; Maetra evaluates it against your active policies and returns a decision - immediately for fast-path outcomes, or after a human responds.
Lifecycle#
create ─▶ evaluate ─┬─▶ approved / rejected / blocked (terminal, signed)
└─▶ pending ─▶ (human decides) ─▶ approved / rejected
└─▶ (timeout) ─▶ expired
| Status | Meaning |
|---|---|
pending | Awaiting a human decision. Poll for the outcome. |
approved | Authorised. A decision_token is issued. |
rejected | A reviewer declined. |
blocked | A policy auto-blocked it (no human needed). |
expired | No decision before the timeout. |
cancelled | Cancelled before resolution. |
Proceed with the action only when status is approved.
Create a checkpoint#
POST /v1/checkpoints — requires scope govern:checkpoints:write.
Evaluated synchronously: a fast-path policy may return a terminal decision in the same response; otherwise you get a pending checkpoint to poll.
Exact policies and decision intelligence
/v1/checkpoints uses the active policies configured in Govern. A policy can use exact saved conditions, or it can use AI agent decision intelligence to evaluate runtime risk.
You do not send a decision_intelligence flag on the checkpoint request. Enable decision intelligence on the policy in the dashboard. The API call stays the same; Maetra applies the policy mode and returns the same checkpoint decision shape.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
action | string | ✓ | The action name, e.g. transfer_funds. |
payload | object | Structured details of the action. | |
agent_name | string | Human-readable caller (use when the agent isn't registered). | |
agent_id | string | Registered agent ID (see Agents). | |
context | string | Free-text context for reviewers. | |
reasoning | string | The agent's reasoning. | |
autonomy_level | string | Agent autonomy level, L0–L5. | |
policy_ids | string[] | Restrict evaluation to these exact or decision-intelligence policies. | |
policy_group_ids | string[] | Restrict evaluation to these policy groups. | |
timeout_seconds | integer | Wall-clock ceiling for a human decision. |
curl -X POST "https://api.maetra.io/v1/checkpoints" \
-H "Authorization: Bearer $MAETRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "delete_customer",
"agent_name": "ops-agent",
"payload": {
"customer_id": "cus_41ab"
},
"reasoning": "GDPR erasure request #8821."
}'
With a registered agent
The call above uses agent_name because the agent isn't registered — the common case. If the agent is registered, pass its agent_id instead (or alongside agent_name) so the checkpoint is attributed to it:
{
"action": "delete_customer",
"agent_id": "agt_5Ab2",
"payload": { "customer_id": "cus_41ab" },
"reasoning": "GDPR erasure request #8821."
}
Policy scope with optional agent identity
agent_id is optional for /v1/checkpoints. When you send only agent_name, Govern still evaluates the action.
For automatic active-policy evaluation:
| Request identity | Policies considered |
|---|---|
Registered agent_id | Organization-wide policies, plus policies assigned to that registered agent. |
agent_name matching a registered agent | Organization-wide policies, plus policies assigned to that registered agent. |
Unknown or unregistered agent_name | Organization-wide policies only. Agent-specific policies do not accidentally run. |
| No agent identity | Organization-wide policies only. |
Use agent_id for stable attribution. Use agent_name for API-only or MCP agents that have not been registered yet. If you pass policy_ids or policy_group_ids, Maetra evaluates that explicit selection. The selection can include exact policies or decision-intelligence policies.
Response
{
"checkpoint_id": "cp_7Yh2Qa",
"agent_id": null,
"agent_name": "ops-agent",
"status": "pending",
"reason": null,
"decision_token": null,
"expires_at": "2026-07-07T12:05:00.000Z",
"evals": [
{ "policy_name": "Destructive actions", "status": "pending", "quorum_required": 2, "quorum_met": 0, "pool_size": 4 }
]
}
| Field | Type | Description |
|---|---|---|
checkpoint_id | string | The checkpoint's ID. |
agent_id / agent_name | string | null | The caller identity you supplied. |
status | enum | pending, approved, rejected, expired, blocked, cancelled. |
reason | string | null | Human or policy reason, when available. |
decision_token | string | null | Signed JWT proving a terminal decision — see Decision tokens. |
expires_at | string | null | ISO 8601 expiry. |
evals | array | Per-policy evaluation detail (below). |
Eval object: policy_id, policy_name, applicability, status, quorum_required, quorum_met, pool_size.
Get a checkpoint (cold poll)#
GET /v1/checkpoints/{id} — scope govern:checkpoints:read. Returns the current state without waiting. Keep ≥1 second between polls of the same checkpoint; prefer the long-poll below.
curl "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa" \
-H "Authorization: Bearer $MAETRA_API_KEY"
Wait for a decision (long-poll)#
GET /v1/checkpoints/{id}/wait — scope govern:checkpoints:read. Holds the connection open until the checkpoint changes state or the hold elapses. The efficient way to wait for a human.
- Query
timeout: hold seconds,1–55(default50). 200— changed; body is the new state.202— no change; reconnect.
curl "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50" \
-H "Authorization: Bearer $MAETRA_API_KEY"
Recommended flow#
POST /v1/checkpoints.- If
statusis already terminal, act on it (and verify the token). - If
pending, long-poll/waituntil terminal. - On
approved, verify the decision token, then act. On anything else, don't.