API Reference Batch 10 — Policy Engine, Compliance Bundles, DLP Rules, SIEM & Kill Switch
API Reference Batch 10 — Policy Engine, Compliance Bundles, DLP Rules, SIEM & Kill Switch
Section titled “API Reference Batch 10 — Policy Engine, Compliance Bundles, DLP Rules, SIEM & Kill Switch”This batch documents five endpoint groups from the platform policy and security administration surface: the policy engine CRUD API, compliance bundle management, DLP rule administration, SIEM connector management, and the kill switch API.
Authentication
Section titled “Authentication”All endpoints require a valid Bearer token with role: admin:
Authorization: Bearer <jwt>Policy Engine
Section titled “Policy Engine”The policy engine API manages packs, rules, chains, and simulations. Source: backend/app/api/policy_packs.py
Policy Packs
Section titled “Policy Packs”List policy packs
Section titled “List policy packs”GET /api/admin/policy-packs/Returns all policy packs (system bundles and org custom packs), ordered by type (bundles first) then name. Includes a computed rule_count.
Response 200 OK:
[ { "id": "550e8400-e29b-41d4-a716-446655440000", "tenant_id": null, "name": "PCI-DSS v4.0 Compliance Bundle", "description": "Payment card industry data security standard rules", "pack_type": "bundle", "compliance_standard": "PCI-DSS", "version": "1.0", "is_active": true, "rule_count": 14, "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T00:00:00Z" }]Create policy pack
Section titled “Create policy pack”POST /api/admin/policy-packs/Creates a new custom (pack_type: "custom") policy pack. Bundle packs are system-managed and cannot be created via this endpoint.
Request body:
{ "name": "Contractor Restrictions", "description": "Rules restricting contractor access to sensitive models", "pack_type": "custom", "compliance_standard": null, "version": "1.0", "is_active": true}Response 201 Created: policy pack object (same schema as list item, rule_count: 0).
Error 400 Bad Request if pack_type: "bundle" is specified.
Get policy pack
Section titled “Get policy pack”GET /api/admin/policy-packs/{pack_id}Returns a single policy pack with its full rule list.
Response 200 OK:
{ "id": "550e8400-...", "name": "Contractor Restrictions", "pack_type": "custom", "rule_count": 3, "rules": [ { "id": "...", "pack_id": "...", "sequence": 0, "name": "Block Claude Opus for contractors", "description": "", "applies_to": "input", "conditions": { "models": ["claude-opus-4"], "user_groups": ["contractors"] }, "action": { "type": "BLOCK", "message": "This model is not available to contractor accounts." }, "is_active": true, "created_at": "...", "updated_at": "..." } ]}Error 404 Not Found if pack does not exist.
Update policy pack
Section titled “Update policy pack”PUT /api/admin/policy-packs/{pack_id}Updates pack metadata. For bundle packs, only is_active can be toggled — name, description, and version are read-only.
Request body (partial update — all fields optional):
{ "name": "Contractor Restrictions v2", "description": "Updated contractor rules", "version": "2.0", "is_active": true}Error 400 Bad Request if attempting to modify bundle metadata.
Delete policy pack
Section titled “Delete policy pack”DELETE /api/admin/policy-packs/{pack_id}Deletes a custom policy pack. Bundle packs cannot be deleted.
Response 204 No Content.
Error 400 Bad Request if the pack is a bundle.
List system bundles
Section titled “List system bundles”GET /api/admin/policy-packs/bundles/Returns only system compliance bundles (read-only packs seeded by the platform).
Policy Rules
Section titled “Policy Rules”Rules belong to a pack. Bundle pack rules cannot be created, modified, or deleted.
List rules
Section titled “List rules”GET /api/admin/policy-packs/{pack_id}/rules/Returns all rules for the pack, ordered by sequence.
Create rule
Section titled “Create rule”POST /api/admin/policy-packs/{pack_id}/rules/Adds a rule to a custom pack.
Request body:
{ "sequence": 0, "name": "Block financial model for contractors", "description": "", "applies_to": "input", "conditions": { "models": ["gpt-4o"], "user_groups": ["contractors"], "channel": ["interactive", "api"] }, "action": { "type": "BLOCK", "message": "Access to GPT-4o is restricted for contractor accounts." }, "is_active": true}applies_to values: "input", "output", "both"
Supported condition fields:
| Field | Type | Description |
|---|---|---|
user_groups | string[] | User must be in ANY of these groups |
entity_types | string[] | DLP entity types (e.g. ["SSN", "CREDIT_CARD"]) |
entity_confidence_min | float | Minimum DLP confidence (0.0–1.0) |
content_regex | string | Regex pattern matched against prompt text |
providers | string[] | Provider identifiers (e.g. ["openai"]) |
models | string[] | Model identifiers (e.g. ["gpt-4o"]) |
user_risk_score_min | float | Minimum CredInt risk score |
intent_complexity | string | "simple" / "medium" / "complex" |
channel | string[] | ["interactive"] / ["api"] / ["interactive", "api"] |
Supported action types:
| Type | Additional fields |
|---|---|
ALLOW | — |
BLOCK | message (string, shown to user) |
CANCEL | message (string) |
REDACT | redact_replacement (string, default "[REDACTED]") |
ROUTE_TO | route_to_model (string) or route_to_tier ("haiku" / "sonnet" / "opus") |
PROMPT | prompt_message (string, governance challenge text) |
ALLOW_WITH_OVERRIDE | override_message (string, shown as notice) |
Response 201 Created: rule object.
Error 400 Bad Request if the pack is a bundle type.
Update rule
Section titled “Update rule”PUT /api/admin/policy-packs/{pack_id}/rules/{rule_id}Partial update — only provided fields are changed.
Error 404 if rule not found in pack. 400 if pack is a bundle.
Delete rule
Section titled “Delete rule”DELETE /api/admin/policy-packs/{pack_id}/rules/{rule_id}Response 204 No Content. Error 400 if bundle pack.
Reorder rules
Section titled “Reorder rules”POST /api/admin/policy-packs/{pack_id}/rules/reorderAtomically reassigns sequence numbers for all rules in the pack.
Request body:
{ "entries": [ { "id": "rule-uuid-1", "sequence": 0 }, { "id": "rule-uuid-2", "sequence": 1 }, { "id": "rule-uuid-3", "sequence": 2 } ]}All rule IDs must belong to the specified pack. Returns the full updated rule list in new sequence order.
Policy Chains
Section titled “Policy Chains”Chains define the ordered sequence of packs to evaluate, and the combining algorithm.
List policy chains
Section titled “List policy chains”GET /api/admin/policy-chains/Returns all chains (user and org scope) with their pack entries.
Response 200 OK:
[ { "id": "chain-uuid", "scope": "org", "combining_algorithm": "first_applicable", "packs": [ { "id": "entry-uuid", "pack_id": "pack-uuid", "pack_name": "PCI-DSS v4.0", "pack_type": "bundle", "rule_count": 14, "sequence": 0, "is_active": true } ], "created_at": "...", "updated_at": "..." }]Update org chain
Section titled “Update org chain”PUT /api/admin/policy-chains/orgReplaces the org-level chain configuration. Creates the chain if it does not exist.
Request body:
{ "packs": [ { "id": "pack-uuid-1", "sequence": 0 }, { "id": "pack-uuid-2", "sequence": 1 } ], "combining_algorithm": "first_applicable"}combining_algorithm values:
| Value | Description |
|---|---|
first_applicable | First terminal match wins (default, firewall model) |
deny_overrides | BLOCK/CANCEL always beats ALLOW regardless of order (XACML-style) |
All existing chain entries are replaced with the provided pack list.
Simulate policy chain
Section titled “Simulate policy chain”POST /api/admin/policy-chains/simulateDry-run policy evaluation against the current org chain. Does not consume quotas or invoke providers.
Request body:
{ "prompt": "What is the patient's SSN?", "provider": "openai", "model": "gpt-4o", "user_groups": ["contractors", "us-east"]}Response 200 OK:
{ "matched": true, "matched_pack_id": "...", "matched_pack_name": "Contractor Restrictions", "matched_rule_id": "...", "matched_rule_name": "Block GPT-4o for contractors", "matched_sequence": 0, "action": { "type": "BLOCK", "message": "..." }, "match_reason": "user_groups matched: ['contractors']", "evaluation_trace": [ { "pack_id": "...", "pack_name": "Contractor Restrictions", "rule_id": "...", "rule_name": "Block GPT-4o for contractors", "sequence": 0, "matched": true, "match_reason": "user_groups matched: ['contractors']" } ]}Note: The full policy simulator (POST /api/admin/policy/simulate) evaluates all policy layers including quotas, DLP, and rate limits. This chain-only endpoint evaluates only the policy pack chain.
Compliance Bundle Management
Section titled “Compliance Bundle Management”Compliance bundles are groups of DLP rules aligned to regulatory frameworks. Source: backend/app/api/compliance_bundles.py
List compliance bundles
Section titled “List compliance bundles”GET /api/admin/compliance-bundles/Query parameters:
| Parameter | Type | Description |
|---|---|---|
enabled | boolean | Filter by enabled status |
framework | string | Filter by regulatory framework code (e.g. "PCI-DSS") |
Response 200 OK: array of bundle objects with rule_count.
Get compliance matrix
Section titled “Get compliance matrix”GET /api/admin/compliance-bundles/matrixReturns the group-by-bundle compliance matrix used by the admin UI. Shows which bundles are assigned to which user groups, with enforcement mode and upgrade availability.
Response 200 OK:
[ { "group_id": "...", "group_name": "Finance", "member_count": 5, "bundles": [ { "bundle_id": "...", "bundle_name": "PCI-DSS", "framework": "PCI-DSS", "enabled": true, "enforcement_mode": "strict", "version_status": "current", "upgrade_available": false, "version": "1.0" } ] }]enforcement_mode: "strict" for seeded (built-in) bundles, "additive" for custom bundles.
version_status: "current" | "update_available" | "custom".
Get compliance bundle
Section titled “Get compliance bundle”GET /api/admin/compliance-bundles/{bundle_id}Returns bundle detail including the full list of associated DLP rules.
Create compliance bundle
Section titled “Create compliance bundle”POST /api/admin/compliance-bundles/Creates a custom bundle (is_seeded: false). Duplicate names are rejected.
Request body:
{ "name": "Internal Data Policy", "description": "Custom rules for internal data handling", "regulatory_framework": "INTERNAL", "enabled": true}Response 201 Created. Writes a compliance audit event.
Update compliance bundle
Section titled “Update compliance bundle”PUT /api/admin/compliance-bundles/{bundle_id}Partial update of bundle metadata. All fields optional.
Response 200 OK. Writes a compliance audit event.
Delete compliance bundle
Section titled “Delete compliance bundle”DELETE /api/admin/compliance-bundles/{bundle_id}Response 204 No Content.
Error 403 Forbidden if the bundle is a seeded (built-in) bundle. Seeded bundles cannot be deleted.
Activate bundle
Section titled “Activate bundle”POST /api/admin/compliance-bundles/{bundle_id}/activateBulk-enables the bundle and all associated DLP rules.
Response 200 OK:
{ "bundle_id": "...", "enabled": true, "rules_updated": 14}Deactivate bundle
Section titled “Deactivate bundle”POST /api/admin/compliance-bundles/{bundle_id}/deactivateBulk-disables the bundle and all associated DLP rules.
Response 200 OK: same schema as activate, with "enabled": false.
List bundle versions
Section titled “List bundle versions”GET /api/admin/compliance-bundles/{bundle_id}/versionsReturns version history ordered by created_at descending (newest first).
Upgrade bundle
Section titled “Upgrade bundle”POST /api/admin/compliance-bundles/{bundle_id}/upgradeUpgrades a seeded bundle to the latest seed definition while preserving any custom-added rules. Creates version snapshots before and after for audit trail.
Response 200 OK:
{ "previous_version": "1.0", "new_version": "1.1", "rules_added": 3, "rules_removed": 1}Error 400 if the bundle is not seeded, no seed definition is found, or the bundle is already at the latest version.
DLP Rule Management
Section titled “DLP Rule Management”Full CRUD for DLP detection rules with version tracking. Source: backend/app/api/dlp_admin.py
List DLP rules
Section titled “List DLP rules”GET /api/admin/dlp-rules/Query parameters:
| Parameter | Type | Description |
|---|---|---|
enabled | boolean | Filter by enabled status |
detector_type | string | Filter by type: regex, ner, llm |
Response 200 OK: array of DLP rule objects.
DLP rule object:
{ "id": "rule-uuid", "detector_name": "Credit Card Number", "detector_type": "regex", "entity_type": "CREDIT_CARD", "action_tier": "redact", "enabled": true, "confidence_threshold": 0.85, "config_json": { "pattern": "\\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})\\b" }}detector_type values: regex, ner (Presidio), llm (GLiNER zero-shot NER)
action_tier values: block, redact, prompt, log_only, none
Create DLP rule
Section titled “Create DLP rule”POST /api/admin/dlp-rules/Creates a rule and writes a version record (change_type: "create").
Request body:
{ "detector_name": "Internal Project Code", "detector_type": "regex", "entity_type": "PROJECT_CODE", "action_tier": "log_only", "enabled": true, "confidence_threshold": 1.0, "config_json": { "pattern": "\\bPROJ-[0-9]{4,6}\\b" }}Response 201 Created.
Get DLP rule
Section titled “Get DLP rule”GET /api/admin/dlp-rules/{rule_id}Response 200 OK. Error 404 if not found in tenant.
Update DLP rule
Section titled “Update DLP rule”PUT /api/admin/dlp-rules/{rule_id}Partial update. Captures old values and writes a version record (change_type: "update").
Delete DLP rule
Section titled “Delete DLP rule”DELETE /api/admin/dlp-rules/{rule_id}Writes a version record (change_type: "delete") before deleting. Response 204 No Content.
List rule version history
Section titled “List rule version history”GET /api/admin/dlp-rules/{rule_id}/versionsReturns all version records for the rule, ordered by changed_at descending.
Version record:
{ "id": "version-uuid", "rule_id": "rule-uuid", "changed_by": "admin-user-uuid", "change_type": "update", "old_values": { "enabled": true, "action_tier": "log_only" }, "new_values": { "enabled": true, "action_tier": "redact" }, "changed_at": "2026-03-13T12:00:00Z"}Export DLP rules
Section titled “Export DLP rules”GET /api/admin/dlp-rules/exportExports all tenant DLP rules as a JSON envelope for backup.
Response 200 OK:
{ "version": "1.0", "exported_at": "2026-03-13T12:00:00Z", "count": 42, "rules": [ ... ]}Import DLP rules
Section titled “Import DLP rules”POST /api/admin/dlp-rules/import?mode=skipBulk-imports rules from a JSON array. Validates regex patterns before persistence.
Query parameter mode:
| Value | Behavior |
|---|---|
skip (default) | Skip rules whose detector_name already exists |
overwrite | Replace existing rules with import data; writes version record |
rename | Create with _importN suffix to avoid collision |
Request body: JSON array of rule objects (same schema as create).
Response 200 OK:
{ "created": 10, "skipped": 2, "overwritten": 0, "errors": [ { "detector_name": "Bad Pattern", "error": "Invalid regex: unterminated group" } ]}Test DLP rule
Section titled “Test DLP rule”POST /api/admin/dlp-rules/testDry-run a rule pattern against sample text without persisting. No database writes.
Request body:
{ "rule_type": "regex", "pattern": "\\b[A-Z]{2}[0-9]{6}\\b", "sample_text": "Employee ID AB123456 accessed the system."}rule_type values: regex, ner, gliner
For ner: pattern is comma-separated entity type labels (e.g. "PERSON,EMAIL_ADDRESS").
For gliner: pattern is comma-separated free-form labels (e.g. "employee id,passport number").
Response 200 OK:
{ "matches": [ { "start": 12, "end": 20, "matched_text": "AB123456", "entity_type": null, "action": "log_only" } ], "match_count": 1, "rule_type": "regex", "valid_pattern": true, "error": null}List available built-in patterns
Section titled “List available built-in patterns”GET /api/admin/dlp-rules/available-patterns?category=piiReturns metadata for built-in DLP patterns grouped by category. Does not return compiled regexes.
category values: secret, pii, financial, medical, infrastructure
Evaluate DLP rule chain
Section titled “Evaluate DLP rule chain”POST /api/admin/dlp-rules/evaluateSimulates the full DLP rule chain (platform rules + org customizations) against sample text for an org context.
Request body:
{ "text": "Please process payment for card 4111111111111111.", "org_id": "tenant-uuid", "group_id": null, "user_id": null}Response 200 OK:
{ "text_length": 52, "org_id": "tenant-uuid", "rules_evaluated": 38, "rules_matched": 1, "final_action": "redact", "matched_rules": [ { "rule_id": "...", "rule_name": "Credit Card Number", "detector_type": "regex", "entity_type": "CREDIT_CARD", "action_tier": "redact", "match_count": 1, "matches": [...], "source": "platform" } ], "suppressed_rule_ids": [], "custom_org_patterns": 0, "decision_trace": [ "Starting evaluation for org_id=..., text_length=52", "Loaded 36 enabled platform rules", "Rule 'Credit Card Number' matched 1 time(s) → action=redact", "Final action determined: redact" ]}SIEM Configuration
Section titled “SIEM Configuration”Manage SIEM connector health and send test events. Source: backend/app/api/siem.py
SIEM connectors are registered at platform startup via environment variables. The SIEM admin API provides health monitoring and test event delivery — connectors are not created or deleted via the API (they are configured through environment variables).
List SIEM connectors
Section titled “List SIEM connectors”GET /api/admin/siem/connectorsReturns all registered connectors with health status and non-sensitive configuration summary.
Response 200 OK:
{ "connectors": [ { "connector_id": "splunk", "display_name": "Splunk HEC", "status": "healthy", "connector_type": "SplunkHECConnector", "config_summary": { "hec_url": "https://splunk.corp.internal:8088", "index": "arbitex_audit" } } ], "total": 1}status values: healthy, degraded, error, not_configured
SIEM health summary
Section titled “SIEM health summary”GET /api/admin/siem/healthAggregate health counts across all connectors.
Response 200 OK:
{ "healthy": 1, "degraded": 0, "error": 0, "not_configured": 1, "total": 2}Test SIEM connector
Section titled “Test SIEM connector”POST /api/admin/siem/test/{connector_id}Sends a synthetic OCSF audit event to the specified connector to verify end-to-end connectivity.
Response 200 OK:
{ "connector_id": "splunk", "success": true, "events_sent": 1, "error": null}Error 404 if connector ID not found.
Kill Switch API
Section titled “Kill Switch API”Instantly disable or re-enable AI providers or individual models without a service restart. Source: backend/app/api/kill_switch.py
Kill switch state is persisted in the model_configs table (kill_switch_disabled_at column) and survives process restarts. Disabled models return a 503-equivalent error to callers immediately.
List provider kill switch state
Section titled “List provider kill switch state”GET /api/admin/kill-switch/providersReturns all providers with per-model kill switch status.
Response 200 OK:
[ { "provider": "openai", "total_models": 5, "kill_switch_disabled_count": 0, "kill_switch_active": false, "models": [ { "id": "model-config-uuid", "provider": "openai", "model_id": "gpt-4o", "display_name": "GPT-4o", "is_active": true, "kill_switch_active": false, "kill_switch_disabled_at": null, "disabled_reason": null } ] }]Disable provider
Section titled “Disable provider”POST /api/admin/kill-switch/providers/{provider}/disableImmediately disables all models for the provider. Writes one audit log entry per model.
Request body:
{ "reason": "security_event"}reason values: maintenance, cost_runaway, security_event, other
Response 200 OK: updated ProviderKillSwitchSummary with kill_switch_active: true.
Error 404 if no catalog entries exist for the provider.
Enable provider
Section titled “Enable provider”POST /api/admin/kill-switch/providers/{provider}/enableRe-enables all models for the provider. No request body required.
Response 200 OK: updated summary with kill_switch_active: false.
Get model kill switch state
Section titled “Get model kill switch state”GET /api/admin/kill-switch/models/{model_config_id}Returns the kill switch state for a single model config entry (by ModelConfig UUID, not model_id string).
Response 200 OK: KillSwitchStateResponse object.
Disable model
Section titled “Disable model”POST /api/admin/kill-switch/models/{model_config_id}/disableImmediately disables a single model.
Request body: { "reason": "maintenance" }
Response 200 OK: updated KillSwitchStateResponse.
Enable model
Section titled “Enable model”POST /api/admin/kill-switch/models/{model_config_id}/enableRe-enables a single model. No request body required.
Response 200 OK: updated KillSwitchStateResponse with kill_switch_active: false.
See also
Section titled “See also”- Governance challenge actions — PROMPT and ALLOW_WITH_OVERRIDE policy actions
- DLP pipeline configuration — how DLP rules are evaluated in the request pipeline
- Compliance bundle administration — compliance matrix and group assignment
- Kill switch operations — runbook for emergency provider disablement
- SIEM configuration guide — environment variable configuration for SIEM connectors
- Policy simulator — simulate full policy stack (quotas, DLP, policy engine) before deploying rules