DocumentationReference

Customer management API

Read decisions and policy revisions, validate policy changes, and automate workspace operations.

Updated 2026-09-22 Read as Markdown
On this page

Authenticate and select a workspace

The base URL is https://api.kastra.ai/api/v1. Customer management uses a user JWT or an authorized operator/device credential, with current workspace membership and route-specific permissions. For automation, create a scoped operator token through the CLI and store it as KASTRA_TOKEN. An environment runtime API key does not grant policy-authoring access.

Send Authorization: Bearer ... and X-Organization-ID: WORKSPACE_UUID. Use an environment UUID in environment_id or X-Environment-ID on routes supporting environment filters; policy authoring also accepts an environment name through X-Environment. Always set the intended environment on writes. Workspace and environment display names are not interchangeable with their UUIDs.

curl --fail-with-body --get 'https://api.kastra.ai/api/v1/environments' \
  -H "Authorization: Bearer $KASTRA_TOKEN" \
  -H "X-Organization-ID: $KASTRA_WORKSPACE_ID"

The response has success: true and a data array. Select the environment you intend to inspect and retain its id; use its name where a policy predicate or MCP argument requires a name.

Decision history

GET /api/v1/decisions returns data: [] for an empty result and a pagination object. GET /api/v1/decisions/{decisionID} reads one authorized decision.

curl --fail-with-body --get 'https://api.kastra.ai/api/v1/decisions' \
  -H "Authorization: Bearer $KASTRA_TOKEN" \
  -H "X-Organization-ID: $KASTRA_WORKSPACE_ID" \
  --data-urlencode "environment_id=$KASTRA_ENVIRONMENT_ID" \
  --data-urlencode 'decision=DENY' \
  --data-urlencode 'source=claude_code' \
  --data-urlencode 'limit=20'
QueryMeaning
environment_idAuthorized environment UUID; omitted scope includes all authorized environments
decisionALLOW, DENY, or PENDING_REVIEW
sourceRecorded origin, such as claude_code, codex_cli, mcp, or proxy
from, toRFC3339 time bounds
model, provider, workload_type, jurisdictionRequest context filters
emailActor email filter; MCP calls this argument actor_email
searchText across reason, model, workload type, and actor email
attr.x-kastra-attr-toolExample per-attribute filter; supply the attribute’s value
shadow_modetrue or false
shadow_deny, degraded, content_scanStrict boolean filters for shadow denials, billing degradation, or scan findings
effectMetered effect: rate_limit or spend_cap
limit, cursorPage size and opaque continuation token

Pass pagination.next_cursor unchanged to the next request and retain the original filters. Stop when it is empty. Treat total_count as a lower bound when total_count_capped is true. Do not interpret pending history as authorization; use the checkpoint’s effective decision.

GET /api/v1/decisions/export accepts the shared context filters, format=json or format=csv, and max_results up to 10,000. Export requires the corresponding entitlement; list-only search and cursor are not export pagination. Narrow large time windows rather than assuming an export contains every matching record. Evidence exports.

Policies

Policy reads require workspace membership. Policy writes require ADMIN or OWNER and applicable plan access. Paths below are relative to /api/v1.

Method and pathInput / result
GET /policiesOptional environment scope, limit (default 20, maximum 100), offset; data array and meta.total, meta.limit, meta.offset
GET /policies/activeExplicit environment scope; reads its active policy
GET /policies/{policyID}Reads a policy by UUID
GET /policies/{policyID}/revisionsReads revision history
GET /policies/{policyID}/revisions/{revisionNumber}Reads one revision
GET /policies/{policyID}/revisions/{rev1}/diff/{rev2}Compares two revisions
GET /policies/{policyID}/exportExports the policy
POST /policies/validateValidates a candidate body; does not activate it
POST /policiesCreates a policy from name, description, deny, required_attributes, default_decision
PUT /policies/{policyID}Updates editable fields and optional change_note; inspect the resulting revision
POST /policies/{policyID}/activateBody: {"revision_number":1}; use the actual reviewed revision
POST /policies/{policyID}/deactivateDeactivates the policy
POST /policies/{policyID}/revisions/{revisionNumber}/rollbackRolls back to a selected revision
POST /policies/{policyID}/promotetarget_environment (name), activate_immediately (boolean), optional change_note
DELETE /policies/{policyID}Deletes the selected policy

The API receives the policy body directly, without the .kastra file’s metadata / spec wrapper. For example, save this as candidate.json:

{
  "name": "docs-validation-example",
  "default_decision": "allow",
  "deny": [{
    "reason": "Block only the harmless documentation marker",
    "jurisdiction": "*",
    "model_prefix": "*",
    "effect": "deny",
    "conditions": [{
      "attribute": "x-kastra-attr-tool-input",
      "operator": "contains",
      "value": "kastra-docs-deny"
    }]
  }]
}
curl --fail-with-body 'https://api.kastra.ai/api/v1/policies/validate' \
  -H "Authorization: Bearer $KASTRA_TOKEN" \
  -H "X-Organization-ID: $KASTRA_WORKSPACE_ID" \
  -H 'X-Environment: docs-test' \
  -H 'Content-Type: application/json' \
  --data-binary @candidate.json

Create docs-test first or substitute an existing test environment. Check the returned validation result and warnings, not just HTTP success. A candidate, a saved revision, and an active revision are distinct states. Follow policy as code for a CLI workflow and policy syntax for operators and effects.

Policy Builder

The Build policies with AI guide walks through conversation, tests and review. These console API routes require a user bearer session with current Admin or Owner membership. Send X-Organization-ID: WORKSPACE_UUID and explicitly select the environment with X-Environment-ID: ENVIRONMENT_UUID. Sessions are private to their author in that workspace and environment; responses use Cache-Control: no-store. Creating a session or sending messages requires AI authoring access. Committing requires policy-authoring access and the entitlements for the proposed effects.

Paths below are relative to /api/v1/policies/builder.

Method and pathInput / result
GET /sessionsLists the author’s unexpired sessions in the selected environment
POST /sessions{} starts an empty additive draft; optional paths selects scope. To edit the current base explicitly, supply base_policy_id and base_revision
GET /sessions/{sessionID}Reads the current session snapshot
PUT /sessions/{sessionID}Current version, complete document, and paths; optional challenge_suites selects independent challenges
DELETE /sessions/{sessionID}Discards the session; leaves any committed policy intact
POST /sessions/{sessionID}/messagesCurrent version, a UUID id, and non-empty content; returns the session while generation continues
GET /sessions/{sessionID}/eventsAuthenticated server-sent events containing session snapshots
POST /sessions/{sessionID}/testsCurrent version and examples; returns session and verification
POST /sessions/{sessionID}/stopStops the running turn; no version field is required
POST /sessions/{sessionID}/rebaseCurrent version; updates the base and invalidates previous verification
POST /sessions/{sessionID}/commitReviewed version, draft_hash, suite_hash, and explicit publish boolean; returns a commit receipt

Scope values are agent_prompt, agent_tool, proxy_prompt, proxy_output, mcp_local, and mcp_hosted. Editing replaces the supplied document and paths; it is not a partial patch. Omitting challenge_suites preserves the selection; [] clears it. Request objects reject unknown fields.

Successful Builder responses are direct JSON, without a success / data wrapper: listing returns an array; create, read, edit, message, stop and rebase return a session; tests return { "session": ..., "verification": ... }; deletion returns { "deleted": true }. A commit receipt contains policy_id, revision, published, and draft_hash. Inspect the receipt to confirm activation. publish: false is available only when creating a policy in an environment without an existing one.

Use the latest returned session version for each versioned request. Retrying a message uses the same UUID and content; reusing its ID with different content conflicts. Open event streams with authenticated fetch: each state event contains a complete session, and its event ID is the session version. Reconnect the stream or fetch the session after a disconnect; reconnecting must not resend the message. A matching commit retry returns the existing receipt.

Invalid input returns 400, missing or expired drafts 404, stale versions or conflicting state 409, and unavailable Builder configuration 503. Keep the draft on a conflict, reload, and rerun tests before reviewing again. These routes are documented here; they are not yet included in the downloadable OpenAPI schema.

Asynchronous AI authoring jobs

These administrator-gated asynchronous job APIs remain available alongside the conversational Builder:

OperationStart routePoll route
Draft one rulePOST /api/v1/policies/draft-rule/jobsGET /api/v1/policies/draft-rule/jobs/{id}
Summarize changePOST /api/v1/policies/draft-change-summary/jobsGET /api/v1/policies/draft-change-summary/jobs/{id}
Narrow a flagged rulePOST /api/v1/decisions/{decisionID}/suggest-policy-fix/jobsGET /api/v1/decisions/{decisionID}/suggest-policy-fix/jobs/{id}

Use a user session and the required AI authoring entitlement. The single-rule request requires a non-empty description; preserve unknown result fields in API clients. Read the asynchronous job status and nested result; an accepted job is not an installed policy. Older synchronous drafting routes are deprecated and remain bounded by the request timeout. Keep drafting failures visible and inspect the error before retrying.

Audit and approvals

GET /api/v1/audit lists administrative events, with environment_id, event_type, entity_type, entity_id, actor_id, and RFC3339 from / to filters. It uses offset pagination: limit defaults to 50 (maximum 100), and offset defaults to zero. The response returns pagination.limit and pagination.offset; advance by the page size and stop on a short page.

Checkpoint lists use a different, opt-in cursor contract. See approval pagination and resolution, including the distinction between runtime readers and authorized human approvers.

Handle errors explicitly

Native errors use success: false, a human-readable error, and a stable code where documented. Handle authentication, authorization, invalid input, conflicts, entitlements, throttling, and service failure separately. A decision query rejected with 422 / invalid_request can require a smaller time range or additional filters. Preserve unknown response fields for forward compatibility.

The downloadable OpenAPI schema includes the runtime contract and selected management reads. This guide covers additional policy operations; internal administration routes are not customer integration endpoints.