Skip to main content

CRUD endpoints

  • POST /api/v1/policies/
  • GET /api/v1/policies/
  • GET /api/v1/policies/{policy_id}
  • PUT /api/v1/policies/{policy_id}
  • DELETE /api/v1/policies/{policy_id}
Policy fields include:
  • Budgets: run_budget, session_budget, action_budgets
  • Lists: denied_actions, allowed_actions
  • Rate limits: rate_limits
  • Scope: scope (global / agent / run / group / mission) and target_id
  • Approvals: require_approval, approval_actions, approval_tags, approval_risk_levels, approval_threshold_usd, approval_timeout_seconds, default_approvers, approval_rules
  • Evidence graph: evidence_requirements, evidence_max_age_seconds, commit_actions, evidence_actions
  • Argument constraints: argument_constraints (per-action JSON Schema), grounding_rules (field-level)
Every successful PUT creates a PolicyVersion snapshot — see Version history below.

Compile from prose / YAML / JSON

Stateless adapter: returns a validated PolicyCreate-shaped dict (or structured errors). Prose and Markdown are routed through Gemini (gemini-2.5-flash); YAML/JSON skip the LLM and validate directly. Full reference: SDK → Prose policies.

Version history

Every PUT /api/v1/policies/{policy_id} creates an immutable PolicyVersion snapshot with status active, archives the previous active version, and updates policy.current_version_id.

List versions

Status values: draft, in_review, active, archived.

Get a version

Review a version

Marks a draft or in_review version as reviewed by the caller.

Rollback to a version

Copies policy_data from the chosen version back onto the policy, archives the current active version, and creates a new active PolicyVersion snapshot. The rollback is itself a versioned event in the history.

Policy exceptions

Time-bound or count-bound carve-outs that let specific agents/runs bypass a policy:
  • GET /api/v1/policies/{policy_id}/exceptions
  • POST /api/v1/policies/{policy_id}/exceptions
  • DELETE /api/v1/policies/{policy_id}/exceptions/{exception_id}

Policy sync (SDK)

Returns enabled policies for the current user. The SDK merges them in scope order (global → agent → run) and applies the most restrictive setting per field.

Server-side decision

The platform, not the SDK, makes the call. decide() is the single source of truth for whether an action proceeds; the SDK’s local policy cache and the /approvals/check pre-flight endpoint below are both advisory shortcuts on top of it, never the enforcement point itself. Returns a Decision:
outcome is one of allow, deny, require_approval. Evaluation runs in a fixed order and stops at the first match:
  1. Kill switch — an active kill switch on the caller’s agent denies unconditionally (kill_switch_active), before any policy is consulted.
  2. Denied list — the action is in a covering policy’s denied_actions (denied_action).
  3. Allowed list — a covering policy sets a non-empty allowed_actions and the action isn’t on it (not_in_allowed_actions). Being on the list only clears this gate; it does not by itself produce allow for a write (see the default below).
  4. Approval rules — a covering policy has require_approval set and the action matches on approval_actions, approval_tags, approval_risk_levels, approval_threshold_usd, or a complex approval_rules entry (policy_requires_approval).
  5. Action budget — the estimated cost for this single call exceeds the policy’s per-action cap in action_budgets (action_budget_exceeded).
  6. Default — with no covering policy (or no earlier step matched): deny (no_policy_for_write) when impact >= medium, allow (advisory_read) otherwise. This is fail-closed: an org with no policy at all still can’t let its agents perform unreviewed writes, and a deny from any earlier step can never be downgraded to require_approval — the steps run in order and stop at the first match, so a hard deny is always final.
Policy scope for decide() is resolved from the caller’s principal (their organization, or their own directly-owned policies, plus the agent id on the request) — global, agent, and group scoped policies apply; run- and mission-scoped policies are out of reach here since decide() takes no run or mission id.

Approval pre-flight check (SDK)

Implemented on top of decide(). Reports {"requires_approval": true, ...} only for the require_approval outcome; an outright allow or deny from decide() both report {"requires_approval": false} since this endpoint’s response shape has no field for denial — actual enforcement of a deny happens at other checkpoints (e.g. ingest’s kill-switch check).

Test alert

Sends a sample alert email to the policy’s default_approvers to verify the channel works.

Simulate

Replays historical actions against the current policy and reports which would have been blocked, escalated, or allowed. Used by the console’s policy preview.

See also