Tenant Policy API
The legacy condition-based tenant-policy API on the Orchestrator, at /api/v1/tenant-policies, as it answers in v11.0.0.
In v11 the tenant policies this API manages (historically "dynamic policies") are read-only, and they decide nothing: one policy decision engine decides every request, from the shipped policy set and your organization's own typed policy documents. Every write on this API answers 409 LEGACY_POLICY_WRITE_FROZEN and names the route to use instead. The reads stay, so you can export what you had before you re-author it, and are removed in a later release. If you are upgrading, read the v10 → v11 Migration Guide.
/api/v1/dynamic-policies is the deprecated spelling of the same routes, served by the same handlers; both spellings carry the headers described under Reading for export. The related cross-tier /api/v1/policies family on the Orchestrator is legacy and read-only in the same way.
Request and response schemas live in the Policy API reference, starting at listTenantPolicies. The /api/v1/policies family is in the Orchestrator API reference.
What replaces it
A condition-based rule of your own (on user attributes, risk, cost, workflow context) is authored in v11 as a typed policy document: through /api/v1/typed-policies or the portal's Policy Authoring page, validated against your deployment's vocabulary, published, and activated by digest. See Typed Policy Authoring. The condition-based policies AxonFlow ships are part of the shipped policy set; Shipped Policy Posture lists them with their actions.
Base URL and authentication
The Agent proxies this family to the Orchestrator:
http://localhost:8080
- Via the Agent (port
8080):Authorization: Basic base64(clientId:clientSecret). The Agent injects the derivedX-Tenant-ID/X-Org-ID/X-Client-IDheaders before proxying, overwriting any client-supplied values. - Direct Orchestrator access (port
8081): the handler reads tenant scope fromX-Tenant-ID, falling back toX-Org-ID. Requests with neither return401with codeUNAUTHORIZED.
Errors use the shape {"error": {"code": "<STRING_CODE>", "message": "..."}}.
Routes
| Method | Path | In v11 |
|---|---|---|
GET | /api/v1/tenant-policies | Read: list, for export |
GET | /api/v1/tenant-policies/{id} | Read: one policy |
GET | /api/v1/tenant-policies/export | Read: export the tenant's policies |
GET | /api/v1/tenant-policies/effective | Read: the enabled rows as v10.x ordered them |
GET | /api/v1/tenant-policies/{id}/versions | Read: version history |
POST | /api/v1/tenant-policies/{id}/test | Removed in v11; see Testing a stored row |
POST | /api/v1/tenant-policies | Write: 409 |
PUT | /api/v1/tenant-policies/{id} | Write: 409 |
DELETE | /api/v1/tenant-policies/{id} | Write: 409 |
POST | /api/v1/tenant-policies/import | Write: 409 |
Writes answer 409
Create, update, delete and import write the legacy policy table, which v11 makes read-only to the application database role. Each answers 409 Conflict:
{
"error": {
"code": "LEGACY_POLICY_WRITE_FROZEN",
"message": "The legacy policy tables are read-only in v11: migrations/core/172 revoked write access from the application role, and this endpoint writes them. Author policies through the typed authoring route at /api/v1/typed-policies instead. Reads on this endpoint are unaffected."
}
}
No licence, edition or upgrade changes this answer. Branch on error.code; the message names the replacement route. A deployment that connects to its database as the owner (AXONFLOW_DB_USE_APP_ROLE=false) is not bound by the revoke, but nothing the v11 engine decides reads the row a write there creates.
Reading for export
These read routes are a deprecated export surface in v11. Every response on these routes (reads, the 409 on writes, 401 and 503) carries Link: </api/v1/typed-policies>; rel="successor-version" and X-AxonFlow-Removed-In: v11.1, and from the v11.0.0 release a Deprecation header (RFC 9745) dated to the release; v11.1 removes the routes. A path or method these routes do not serve (404, 405) carries none of them.
The read routes answer as they did in v10.x, so an integration can export the rows it had before re-authoring them.
Export
curl "http://localhost:8080/api/v1/tenant-policies/export" \
-H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)"
200 with {"policies": [...], "exported_at": "...", "tenant_id": "..."}, filtered to dynamic-* and media-* policies. Keep this file: it is the record of what your tenant enforced in v10.x.
List and filter
| Query param | Notes |
|---|---|
type | Free-form type filter |
category | Must start with dynamic- or media-; any other prefix is 400 (VALIDATION_ERROR) |
search | Search term |
sort_by, sort_dir | Sort field and direction |
page | Page number, default 1 |
limit | Page size, max 100 (page_size is the deprecated alias) |
enabled | true or false |
List responses return a policies array plus pagination. Each policy resource carries:
| Field | Notes |
|---|---|
id | Policy ID |
name, description | Display name and optional description |
type | content, user, risk, cost, context_aware, media, rate-limit, budget, time-access, role-access, mcp or connector |
category | A dynamic-* or media-* category |
tier | system, organization, or tenant. tenant and organization are the rows your organization authored |
conditions | Condition list: each a field, an operator and a value |
actions | Action list: each a type (alert, block, log, modify_risk, redact, require_approval, route, warn) and an optional config |
priority | Evaluation priority in v10.x |
enabled | Whether the row was active in v10.x |
version | Current version |
tenant_id, organization_id | Scope |
tags | Optional tags |
created_at, updated_at, created_by, updated_by, deleted_at | Timestamps and attribution |
A stored JSON null conditions value, used by platform-seeded rows, means the row applied to everything in v10.x; an explicitly empty list means v10.x excluded the row from evaluation.
Version history
GET /api/v1/tenant-policies/{id}/versions returns versions, each with the complete policy resource at that version in snapshot, plus change_type (create, update, enable, disable, delete), change_summary, changed_by and changed_at.
Testing a stored row
POST /api/v1/tenant-policies/{id}/test is removed in v11: it evaluated a legacy row through the legacy engine, and v11 has no legacy engine to answer for. To check what a policy decides, use policy simulation and policy testing, which answer with the engine that enforces.
Related Docs
- Typed Policy Authoring
- Shipped Policy Posture
- System Policy API: the legacy pattern-based family, read-only in v11 too
- Policy Templates API
- Overrides API
