Policy Engine API
The Policy Engine API lets admins build and manage the full policy stack: packs containing rules, chains that assemble packs in priority order, and a simulation endpoint for safe pre-flight testing. All endpoints require admin authentication (Authorization: Bearer <admin-token>).
Concepts
Section titled “Concepts”Policy packs and rules
Section titled “Policy packs and rules”A policy pack is a named, versioned container of rules. Rules within a pack are evaluated in ascending sequence order. Each rule declares:
- conditions — what must match (entity types, regex, provider/model, risk score, user group)
- applies_to —
input,output, orboth - action — the terminal action taken on a match (
ALLOW,BLOCK,CANCEL,REDACT,ROUTE_TO)
All active conditions within a single rule are ANDed. The first rule whose conditions all match fires its action; subsequent rules in the same pack are not evaluated.
Pack types:
| Type | Description |
|---|---|
custom | Tenant-created packs — fully editable |
bundle | System-supplied compliance bundles — rules are read-only |
template | Instantiated from a policy template |
Policy chains
Section titled “Policy chains”A chain assembles multiple packs into an ordered sequence for a given scope. Two scopes exist:
| Scope | Description |
|---|---|
org | The organisation-level primary chain — applies to all users |
user | Per-user personal override chain — evaluated before the org chain |
During evaluation, the user chain is checked first. If no terminal action is reached, the org chain is evaluated next.
Combining algorithms
Section titled “Combining algorithms”Each chain has a combining_algorithm:
| Algorithm | Behaviour |
|---|---|
first_applicable | Firewall default. Evaluation stops at the first matched terminal action. |
deny_overrides | XACML-style. All rules are evaluated; any BLOCK or CANCEL takes precedence over ALLOW. |
Effective policy resolution
Section titled “Effective policy resolution”The fully resolved policy for a specific user combines the user chain, org chain, and all System Default settings via a three-level cascade:
System Default → Group (lowest priority) → Org chain (policies) → User chain (personal overrides, highest priority)Policy Packs
Section titled “Policy Packs”List packs
Section titled “List packs”GET /api/admin/policy-packs/Returns all packs visible to the tenant — both custom packs and system bundles.
Response 200 OK
[ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "tenant_id": "9c0e1d2f-...", "name": "PCI-DSS Baseline", "description": "Blocks transmission of PANs and CVVs.", "pack_type": "bundle", "compliance_standard": "PCI-DSS", "version": "1.0.0", "is_active": true, "rule_count": 8, "created_at": "2025-11-01T00:00:00Z", "updated_at": "2026-01-15T12:00:00Z" }]Create a pack
Section titled “Create a pack”POST /api/admin/policy-packs/Creates a new custom pack. Bundle and template packs cannot be created via this endpoint.
Request body
{ "name": "Internal Data Policy", "description": "Prevents leaking confidential project names.", "compliance_standard": null}Response 201 Created — returns the created pack object.
Get pack detail
Section titled “Get pack detail”GET /api/admin/policy-packs/{id}Returns the pack metadata plus the full ordered list of rules.
Response 200 OK
{ "id": "3fa85f64-...", "name": "Internal Data Policy", "pack_type": "custom", "version": "1.0.0", "is_active": true, "rule_count": 2, "rules": [ { "id": "a1b2c3d4-...", "name": "Block project code names", "sequence": 1, "applies_to": "input", "conditions": { "regex_patterns": ["Project (?:Apollo|Hermes|Athena)"] }, "action": { "type": "BLOCK", "message": "Confidential project names are not permitted." }, "is_active": true } ]}Update pack metadata
Section titled “Update pack metadata”PUT /api/admin/policy-packs/{id}Updates the pack name, description, or is_active flag. Only custom packs can be updated.
Request body (all fields optional)
{ "name": "Internal Data Policy v2", "description": "Updated description.", "is_active": false}Response 200 OK — returns the updated pack.
Delete a pack
Section titled “Delete a pack”DELETE /api/admin/policy-packs/{id}Permanently deletes a custom pack and its rules. Returns 204 No Content.
System bundles cannot be deleted.
List rules
Section titled “List rules”GET /api/admin/policy-packs/{id}/rules/Returns all rules for the specified pack, ordered by sequence.
Add a rule
Section titled “Add a rule”POST /api/admin/policy-packs/{id}/rules/Adds a new rule to the pack. The rule is appended at the end of the sequence unless sequence is specified.
Request body
{ "name": "Redact SSN on output", "description": "Replaces detected SSNs in model responses.", "sequence": 5, "applies_to": "output", "conditions": { "entity_types": ["ssn"], "min_risk_score": 0.8 }, "action": { "type": "REDACT", "replacement": "[SSN REDACTED]" }, "is_active": true}Condition fields
| Field | Type | Description |
|---|---|---|
entity_types | string[] | DLP entity type labels (e.g. "credit_card", "ssn", "api_key") |
regex_patterns | string[] | One or more regex patterns — any match fires |
providers | string[] | Limit to specific AI providers (e.g. "openai", "anthropic") |
models | string[] | Limit to specific model IDs |
user_groups | string[] | Limit to users in these groups |
min_risk_score | float | Minimum DLP confidence score (0.0–1.0) |
Action types
| Action type | Additional fields | Description |
|---|---|---|
ALLOW | — | Explicitly permit; stops chain evaluation |
BLOCK | message | Reject the request/response with a 400 |
CANCEL | message | Cancel the streaming response mid-flight |
REDACT | replacement | Replace matched spans in the text |
ROUTE_TO | endpoint_id | Forward to an alternative provider endpoint |
Response 201 Created — returns the created rule.
Update a rule
Section titled “Update a rule”PUT /api/admin/policy-packs/{id}/rules/{rule_id}Updates an existing rule. Only provided fields are modified.
Response 200 OK
Delete a rule
Section titled “Delete a rule”DELETE /api/admin/policy-packs/{id}/rules/{rule_id}Returns 204 No Content.
Reorder rules
Section titled “Reorder rules”POST /api/admin/policy-packs/{id}/rules/reorderSets a new sequence for one or more rules in a single atomic operation.
Request body
{ "entries": [ { "id": "a1b2c3d4-...", "sequence": 1 }, { "id": "b2c3d4e5-...", "sequence": 2 }, { "id": "c3d4e5f6-...", "sequence": 3 } ]}Response 200 OK — returns the full updated rule list.
Chains
Section titled “Chains”Get org policy chain
Section titled “Get org policy chain”GET /api/admin/policy-chains/Returns the organisation’s policy chain including all referenced pack summaries in sequence order.
Response 200 OK
{ "id": "chain-uuid-...", "scope": "org", "combining_algorithm": "first_applicable", "packs": [ { "id": "entry-uuid-...", "pack_id": "pack-uuid-...", "pack_name": "PCI-DSS Baseline", "pack_type": "bundle", "rule_count": 8, "sequence": 1, "is_active": true } ], "created_at": "2025-11-01T00:00:00Z", "updated_at": "2026-03-10T08:00:00Z"}Update org chain
Section titled “Update org chain”PUT /api/admin/policy-chains/orgReplaces the chain’s pack order and combining algorithm. All existing entries are replaced.
Request body
{ "packs": [ { "id": "pack-uuid-a", "sequence": 1 }, { "id": "pack-uuid-b", "sequence": 2 } ], "combining_algorithm": "deny_overrides"}Response 200 OK
Simulate policy evaluation
Section titled “Simulate policy evaluation”POST /api/admin/policy-chains/simulateEvaluates a hypothetical prompt against the org chain without routing to any AI provider. Returns the match result and a full evaluation trace showing which rules were checked and why.
Request body
{ "prompt": "Please send me a list of all employees with their SSNs.", "provider": "openai", "model": "gpt-4o", "user_groups": ["finance"]}Response 200 OK
{ "matched": true, "matched_pack_id": "pack-uuid-...", "matched_pack_name": "PII Baseline", "matched_rule_id": "rule-uuid-...", "matched_rule_name": "Block SSN requests", "matched_sequence": 2, "action": { "type": "BLOCK", "message": "PII requests are not permitted." }, "match_reason": "entity_type=ssn matched", "evaluation_trace": [ { "pack_id": "pack-uuid-...", "pack_name": "PII Baseline", "rule_id": "rule-uuid-...", "rule_name": "Allow finance group PII preview", "sequence": 1, "matched": false, "match_reason": null }, { "pack_id": "pack-uuid-...", "pack_name": "PII Baseline", "rule_id": "rule-uuid-...", "rule_name": "Block SSN requests", "sequence": 2, "matched": true, "match_reason": "entity_type=ssn matched" } ]}The trace lists every rule evaluated, in order, until the chain terminates. Use this to debug unexpected allow/block decisions before deploying policy changes.
System Bundles
Section titled “System Bundles”List system bundles
Section titled “List system bundles”GET /api/admin/policy-packs/bundles/Returns all system-supplied policy bundles available for inclusion in org chains.
Effective Policy
Section titled “Effective Policy”Get effective policy for a user
Section titled “Get effective policy for a user”GET /api/admin/policy/effective/{user_id}Resolves the fully effective policy for a specific user by cascading System Default → Group → User. Each setting in the response includes a source field indicating where the value originated.
Response 200 OK
{ "user_id": "user-uuid-...", "quotas": { "daily_token_limit": { "value": 500000, "source": "group" }, "monthly_token_limit": { "value": 5000000, "source": "system_default" } }, "model_access": { "allowed_providers": { "value": ["openai", "anthropic"], "source": "org_chain" } }, "dlp_rules": { "source": "org_chain" }, "content_filters": { "source": "org_chain" }}Errors
| Status | Condition |
|---|---|
404 Not Found | User ID does not exist in the tenant |
Policy Templates
Section titled “Policy Templates”Policy templates provide reusable configuration bundles that can be applied to groups with a single API call.
List templates
Section titled “List templates”GET /api/admin/policy-templatesGet template
Section titled “Get template”GET /api/admin/policy-templates/{template_id}Create template
Section titled “Create template”POST /api/admin/policy-templatesRequest body
{ "name": "Healthcare Baseline", "description": "HIPAA-aligned defaults for clinical users.", "template_type": "compliance", "config": { "dlp_rules": ["phi_detector"], "content_filters": ["medical_jailbreak"] }}Update template
Section titled “Update template”PUT /api/admin/policy-templates/{template_id}Delete template
Section titled “Delete template”DELETE /api/admin/policy-templates/{template_id}Returns 204 No Content.
Apply template to a group
Section titled “Apply template to a group”POST /api/admin/policy-templates/{template_id}/apply/{group_id}Applies the template’s configuration to the specified group. Returns an ApplyTemplateResponse summarising which settings were modified.
Error codes
Section titled “Error codes”| Status | Meaning |
|---|---|
400 Bad Request | Invalid request body or rule validation failure |
403 Forbidden | Caller is not an admin |
404 Not Found | Pack, rule, chain, or template not found |
409 Conflict | Attempt to mutate a read-only bundle pack |