Managing Policies
This page is the complete reference for every policy field in AxonFlow and the two ways to manage policies: the customer portal and the policy CRUD API. Use it when you need to know exactly what a field means, whether you can change it, and how to create or edit a policy.
AxonFlow has two families of policies:
| Family | Where it lives | Managed in API as | Typical use |
|---|---|---|---|
| System policies (also called static policies) | The Agent | /api/v1/static-policies | Fast, pattern-based checks: PII detection, SQL-injection blocking, secret-leak detection |
| Tenant policies (also called dynamic policies) | The Orchestrator | /api/v1/dynamic-policies | Context-aware rules built from conditions and actions: risk, cost, user, content, and media governance |
In the portal these appear as Static (read-only) and Dynamic (editable) sources. Both families share the same three-tier hierarchy — system, organization, and tenant — described in Policy Hierarchy.
Policy Field Reference
System (static) policy fields
System policies are pattern-based rules returned by /api/v1/static-policies. The table below lists every field, whether you can set it, and what it controls.
| Field | Type | Settable? | Meaning | Valid values |
|---|---|---|---|---|
name | string | Settable | Human-readable policy name | Required on create; up to 255 characters |
description | string | Settable | Plain-English explanation of what the policy detects and why it exists | Optional free text |
category | string | Settable | Classification that groups the policy (see Policy Syntax → Categories) | Required on create, e.g. security-sqli, pii-global, pii-us, code-secrets, sensitive-data |
pattern | string | Settable | Regular expression matched against request content | Required on create; Go (RE2) regular expression |
action | string | Settable | What the Agent does when the pattern matches | block, redact, warn, log, require_approval |
severity | string | Settable | How serious a match is | low, medium, high, critical (default medium) |
priority | integer | Settable | Evaluation order — higher values are evaluated first | Default 50 for system policies |
enabled | boolean | Settable | Whether the policy is active | true / false (default true) |
tags | array of strings | Settable | Free-form labels for grouping (for example compliance:hipaa) | Optional |
tier | string | Settable on create only | Which tier the policy belongs to | organization or tenant — system is rejected by the API |
organization_id | string | Settable on create only | Organization scope for organization-tier policies | Required when tier is organization |
risk_level | string | System-managed | Risk classification used by the session-override contract. Seeded from the policy's category | low, medium, high, critical (default medium) |
allow_override | boolean | System-managed | Whether an administrator may relax this policy with a session override. Forced to false whenever risk_level is critical | true / false |
id | string (UUID) | Read-only | Internal unique identifier | Assigned by AxonFlow |
policy_id | string | Read-only | Stable string identifier (slug) | Assigned by AxonFlow |
tenant_id | string | Read-only | Tenant the policy belongs to | Derived from your credentials |
version | integer | Read-only | Increments on every change | Assigned by AxonFlow |
created_at / updated_at | string (ISO 8601) | Read-only | Creation and last-modified timestamps | Assigned by AxonFlow |
created_by / updated_by | string | Read-only | Who created or last changed the policy | From the X-User-ID header |
deleted_at | string (ISO 8601) | Read-only | Set when a policy is soft-deleted | Assigned by AxonFlow |
metadata | object | Read-only | Structured metadata attached by AxonFlow | Assigned by AxonFlow |
When you read system policies through /api/v1/static-policies/effective, each policy also carries override information so you can see what is actually enforced:
| Field | Type | Meaning |
|---|---|---|
has_override | boolean | Whether an override is in effect for this policy |
override_action | string | The action the override enforces in place of action |
override_enabled | boolean | The enabled state the override enforces in place of enabled |
override_expires_at | string (ISO 8601) | When a temporary override reverts |
override_reason | string | Why the override was created |
When has_override is true, the override's override_action and override_enabled are what the Agent enforces; otherwise the policy's own action and enabled apply. (The customer portal's unified policy view surfaces the same result as effective_action and effective_enabled fields.)
You cannot create, modify, or delete system-tier policies through the API or the portal. They are maintained centrally and form your immutable security baseline. To change how a system policy behaves, create an override (Enterprise) — see Overriding system policies. The full catalog is documented in System Policies Reference.
Tenant (dynamic) policy fields
Tenant policies are condition-and-action rules returned by /api/v1/dynamic-policies. These are the policies you author yourself.
| Field | Type | Settable? | Meaning | Valid values |
|---|---|---|---|---|
name | string | Settable | Human-readable policy name | Required; 3–100 characters |
description | string | Settable | Plain-English explanation of the rule | Optional; up to 500 characters |
type | string | Settable | The kind of policy, which determines the icon and grouping in the portal | Required; one of content, user, risk, cost, context_aware, media, rate-limit, budget, time-access, role-access, mcp, connector |
category | string | Settable | Classification for filtering and reporting | Required on the /api/v1/dynamic-policies endpoint; must start with dynamic- (for example dynamic-risk, dynamic-compliance) or media- (for example media-pii, media-safety) |
conditions | array | Settable | The rules that decide whether the policy matches (see Conditions) | Required; at least one condition |
actions | array | Settable | What happens when all conditions match (see Actions) | Required; at least one action |
priority | integer | Settable | Evaluation order — higher values are evaluated first | 0–1000 |
enabled | boolean | Settable | Whether the policy is active | true / false |
tags | array of strings | Settable | Free-form labels for grouping | Optional |
tier | string | Settable on create only | Which tier the policy belongs to | organization or tenant — system is rejected by the API |
id | string (UUID) | Read-only | Internal unique identifier | Assigned by AxonFlow |
tenant_id | string | Read-only | Tenant the policy belongs to | Derived from your credentials |
organization_id | string | Read-only (set from tier scope) | Organization scope for organization-tier policies | Assigned by AxonFlow |
version | integer | Read-only | Increments on every change | Assigned by AxonFlow |
created_at / updated_at | string (ISO 8601) | Read-only | Creation and last-modified timestamps | Assigned by AxonFlow |
created_by / updated_by | string | Read-only | Who created or last changed the policy | From the X-User-ID header |
deleted_at | string (ISO 8601) | Read-only | Set when a policy is soft-deleted | Assigned by AxonFlow |
Conditions
A condition is an object with three keys. All conditions in a policy must match for the policy to trigger.
{ "field": "risk_score", "operator": "greater_than", "value": 0.8 }
| Key | Meaning |
|---|---|
field | The request attribute to inspect |
operator | How to compare the field to value |
value | The value (or list of values) to compare against |
Supported field values:
query, response, user.email, user.role, user.department, user.tenant_id, risk_score, request_type, connector, cost_estimate, the media-governance fields (media.has_faces, media.face_count, media.has_biometric_data, media.nsfw_score, media.violence_score, media.content_safe, media.document_type, media.is_sensitive_document, media.has_pii, media.pii_types, media.has_extracted_text, media.extracted_text_length), and the retry-aware workflow fields (step.gate_count, step.completion_count, step.prior_completion_status, step.prior_output_available, step.last_decision, step.first_attempt_age_seconds, step.idempotency_key).
Policies that reference any step.* field require an Evaluation or Enterprise license. Creating, updating, or importing such a policy on the Community edition returns a tier error.
Supported operator values:
equals, not_equals, contains, not_contains, contains_any, regex, greater_than, less_than, in, not_in.
Actions
An action is an object with a type and an optional config:
{ "type": "redact", "config": { "fields": ["ssn", "salary"] } }
The canonical action vocabulary accepted by the policy API is:
type | What it does | Typical config |
|---|---|---|
block | Reject the request | { "reason": "…" } |
redact | Mask the listed fields in the response | { "fields": ["field1", "field2"] } |
require_approval | Pause for human approval (HITL) | — |
warn | Allow the request but record a warning | — |
log | Allow the request and record an audit entry | — |
alert | Send an alert to your monitoring system | Varies by alerting integration |
route | Apply an LLM routing rule | Varies by routing rule |
modify_risk | Adjust the computed risk score | { "modifier": 1.5 } |
allow is the implicit default when no policy matches; it is not something you set as an action type.
How risk is expressed
A common point of confusion is how "risk" maps to fields. AxonFlow models risk in three distinct ways, and none of them is a free-form numeric field you set on a policy:
risk_scoreis a request attribute computed at evaluation time (a value from0.0to1.0). You reference it in a condition, for example{ "field": "risk_score", "operator": "greater_than", "value": 0.8 }.modify_riskis an action that nudges that computed score up or down for downstream policies.risk_levelis a system-assigned classification (low/medium/high/critical) on system policies that drives the session-override contract. It is not settable through the API.
The risk-scored example below shows the condition-based pattern in practice.
Managing policies in the portal
The Policies page in the customer portal gives you a single view of every system and tenant policy. (In an in-VPC deployment the page is titled Platform Policies and changes apply across all tenants.)
The summary and the list
At the top, four cards summarize your policies: Total Policies, Static (read-only), Dynamic (editable), and Enabled. Below them, each policy row shows:
- the policy name and a version badge (for example
v3); - a 🔒 lock icon when the policy is read-only (system-managed);
- a source badge (Static or Dynamic) and a tier badge (System, Organization, or Tenant);
- for system policies, the category and severity badges plus a preview of the regex pattern;
- for tenant policies, the type badge and the priority;
- an Overridden badge when an override is active, and a Disabled badge when the policy is off;
- the description and the last-updated time.
Filtering
Use the filter bar to narrow the list by Source (All / Static / Dynamic), Tier (System / Organization / Tenant), Status (Enabled / Disabled), and — depending on the source — Type (for dynamic policies) or Category (for static policies).
What you can edit
| Action | System (static) policies | Tenant (dynamic) policies |
|---|---|---|
| Create | Not available (system-managed) | Create Policy button |
| Edit | Not available | Edit button (name, description, type, conditions, actions, priority) |
| Enable / Disable | Not available | Enable / Disable button |
| Delete | Not available | Delete button (with confirmation) |
| Test | Not available | Test button |
| Preview Impact | Not available | Preview Impact button |
| Version history | Not available | History button |
| Override | Override / Remove Override (Enterprise) | Not applicable |
System policies show a System managed label instead of edit controls.
Creating or editing a tenant policy
- Click Create Policy (or Edit on an existing tenant policy).
- Give the policy a name and an optional plain-English description.
- Choose a type (content, user, risk, cost, …) and set a priority.
- Add one or more conditions (field, operator, value) and one or more actions (block, redact, require approval, …).
- Save. The policy takes effect within seconds.
Testing and previewing
- Test runs the policy against a sample query and tells you whether it matched, whether the request would be blocked, which actions would fire, and the evaluation time.
- Preview Impact estimates how the policy would affect recent traffic before you enable it.
- Simulate Policies (top of the page) runs a what-if evaluation across your policy set.
Overriding system policies
Because system policies are read-only, Enterprise customers change their behavior with an override rather than an edit:
- Click Override on a system policy.
- Optionally choose an Action Override (you can only make a policy more restrictive, or disable it) and/or an Enabled Override.
- Enter a required Override Reason for the audit trail, and optionally an Expiration Date for a temporary override.
- Save. The policy now shows an Overridden badge and its effective action. Use Remove Override to revert.
Import and export
Export downloads your tenant policies as JSON. Import uploads a JSON file and lets you choose how to handle duplicates (skip, overwrite, or error). Up to 100 policies can be imported at once.
Managing policies via the API
Authentication and base URL
Policy endpoints are exposed by the Agent (default port 8080) and authenticated with your client credentials:
Authorization: Basic <base64(CLIENT_ID:CLIENT_SECRET)>
Your tenant is derived from those credentials. On mutating requests, add X-User-ID so changes are attributed in the audit trail.
Endpoints
Tenant (dynamic) policies — author your own condition-and-action rules:
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/dynamic-policies | List policies |
POST | /api/v1/dynamic-policies | Create a policy |
GET | /api/v1/dynamic-policies/{id} | Get one policy |
PUT | /api/v1/dynamic-policies/{id} | Update a policy |
DELETE | /api/v1/dynamic-policies/{id} | Delete a policy (soft delete) |
POST | /api/v1/dynamic-policies/{id}/test | Test a policy against sample input |
GET | /api/v1/dynamic-policies/{id}/versions | List version history |
POST | /api/v1/dynamic-policies/import | Bulk import |
GET | /api/v1/dynamic-policies/export | Bulk export |
GET | /api/v1/dynamic-policies/effective | Effective policies for the tenant |
System (static) policies — read the baseline, manage your own custom pattern rules:
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/static-policies | List policies |
POST | /api/v1/static-policies | Create a custom pattern policy |
GET | /api/v1/static-policies/{id} | Get one policy |
PUT | /api/v1/static-policies/{id} | Update a non-system policy |
DELETE | /api/v1/static-policies/{id} | Delete a non-system policy |
PATCH | /api/v1/static-policies/{id} | Toggle enabled |
POST | /api/v1/static-policies/test | Test a regex pattern against inputs |
GET | /api/v1/static-policies/effective | Effective policies with overrides applied |
See Tenant Policy API and System Policy API for the full wire reference. The settable-vs-read-only split is exactly as listed in the field reference above.
Example 1: a custom PII policy
Create a tenant policy that redacts sensitive fields whenever a request mentions them. This is a content policy in the dynamic-compliance category that fires a redact action.
curl -X POST http://localhost:8080/api/v1/dynamic-policies \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'CLIENT_ID:CLIENT_SECRET' | base64)" \
-H "X-User-ID: [email protected]" \
-d '{
"name": "Redact customer PII",
"description": "Mask SSN, salary, and medical record fields in responses",
"type": "content",
"category": "dynamic-compliance",
"priority": 900,
"enabled": true,
"conditions": [
{ "field": "query", "operator": "contains_any", "value": ["ssn", "salary", "medical_record"] }
],
"actions": [
{ "type": "redact", "config": { "fields": ["ssn", "salary", "medical_record"] } }
]
}'
Response (201 Created):
{
"policy": {
"id": "6f1c2e8a-9b3d-4f7a-8c21-2d4e6a8b0c11",
"name": "Redact customer PII",
"description": "Mask SSN, salary, and medical record fields in responses",
"type": "content",
"category": "dynamic-compliance",
"tier": "tenant",
"priority": 900,
"enabled": true,
"version": 1,
"conditions": [
{ "field": "query", "operator": "contains_any", "value": ["ssn", "salary", "medical_record"] }
],
"actions": [
{ "type": "redact", "config": { "fields": ["ssn", "salary", "medical_record"] } }
],
"created_at": "2026-06-12T10:00:00Z",
"updated_at": "2026-06-12T10:00:00Z"
}
}
List it back, filtering by category:
curl "http://localhost:8080/api/v1/dynamic-policies?category=dynamic-compliance" \
-H "Authorization: Basic $(echo -n 'CLIENT_ID:CLIENT_SECRET' | base64)"
Test it against a sample query before relying on it:
curl -X POST http://localhost:8080/api/v1/dynamic-policies/6f1c2e8a-9b3d-4f7a-8c21-2d4e6a8b0c11/test \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'CLIENT_ID:CLIENT_SECRET' | base64)" \
-d '{ "query": "Show me the salary for employee 42" }'
{
"matched": true,
"blocked": false,
"actions": [
{ "type": "redact", "config": { "fields": ["ssn", "salary", "medical_record"] } }
],
"explanation": "Policy 'Redact customer PII' matched: all 1 conditions evaluated to true",
"eval_time_ms": 0.21
}
To make the rule stricter later, update it (only the fields you send change):
curl -X PUT http://localhost:8080/api/v1/dynamic-policies/6f1c2e8a-9b3d-4f7a-8c21-2d4e6a8b0c11 \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'CLIENT_ID:CLIENT_SECRET' | base64)" \
-H "X-User-ID: [email protected]" \
-d '{ "priority": 950 }'
And remove it when it is no longer needed:
curl -X DELETE http://localhost:8080/api/v1/dynamic-policies/6f1c2e8a-9b3d-4f7a-8c21-2d4e6a8b0c11 \
-H "Authorization: Basic $(echo -n 'CLIENT_ID:CLIENT_SECRET' | base64)" \
-H "X-User-ID: [email protected]"
A successful delete returns 204 No Content.
Example 2: a risk-scored block policy
Block any request whose computed risk score exceeds a threshold. This is a risk policy that reads the risk_score request attribute in a condition and fires a block action.
curl -X POST http://localhost:8080/api/v1/dynamic-policies \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'CLIENT_ID:CLIENT_SECRET' | base64)" \
-H "X-User-ID: [email protected]" \
-d '{
"name": "Block high-risk queries",
"description": "Reject requests whose risk score exceeds the safety threshold",
"type": "risk",
"category": "dynamic-risk",
"priority": 1000,
"enabled": true,
"conditions": [
{ "field": "risk_score", "operator": "greater_than", "value": 0.8 }
],
"actions": [
{ "type": "block", "config": { "reason": "Query risk score exceeds safety threshold" } }
]
}'
The policy matches when the request's risk_score is above 0.8 and blocks it. You can combine the risk condition with others — for example, only block high-risk requests from a specific role by adding { "field": "user.role", "operator": "equals", "value": "contractor" } to the conditions array (remember: all conditions must match).
Validation and errors
Validation failures return 400 with a VALIDATION_ERROR code and per-field details:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{ "field": "name", "message": "Name must be between 3 and 100 characters" },
{ "field": "actions[0]", "message": "invalid action type: deny" }
]
}
}
Common rules to keep in mind:
nameis required (3–100 characters);descriptionis capped at 500 characters.typemust be one of the values in the field reference.- At least one
conditionand oneactionare required;prioritymust be0–1000. - Each action
typemust be in the canonical action vocabulary. - Attempting to create a
system-tier policy returns403(System policies cannot be created via API).
Editions and limits
- System-tier policies are immutable on every edition — you override them (Enterprise) rather than edit them.
- Organization-tier policies require an Evaluation or Enterprise license.
- Tenant-tier policies are available on every edition; Community and Evaluation have a per-tenant policy-count limit, while paid editions are unlimited. Exceeding a limit returns a tier error with an upgrade link.
Compare what each edition unlocks in Community vs Evaluation vs Enterprise.
Related
- Policy Syntax — field structure, categories, and regex pattern reference
- System Policies Reference — the full catalog of built-in policies
- Policy Hierarchy — how system, organization, and tenant tiers combine
- Tenant Policy API and System Policy API — full wire reference
- Policy Examples — ready-to-use policy templates
- Policy Testing — test and validate policies before rollout
- SDK Methods — manage policies from the SDKs
