DLP Rules API
The DLP Rules API manages the detection rules that power the three-tier DLP pipeline. All endpoints are admin-only (Authorization: Bearer <admin-token>).
DLP pipeline overview
Section titled “DLP pipeline overview”Every prompt and response passes through three detection tiers in sequence:
| Tier | Detector | Model | Best for |
|---|---|---|---|
| 1 | Regex | detector_type: "regex" | High-performance pattern matching (credit cards, SSNs, API keys) |
| 2 | NER (Presidio) | detector_type: "ner" | Named-entity recognition — names, locations, organisations |
| 3 | DeBERTa v3 | detector_type: "llm" | Semantic / context-sensitive detection (unreliable code patterns, obfuscated data) |
Rules at each tier share the same CRUD API surface. The detector_type field selects which engine evaluates the rule.
Action tiers
Section titled “Action tiers”action_tier | Effect |
|---|---|
log_only | Record the match in the audit log; pass the request through |
redact | Replace matched spans before forwarding (input) or before delivery (output) |
prompt | Pause the request and surface a human-in-the-loop decision (requires PROMPT governance) |
block | Reject the request/response with HTTP 400 |
When multiple rules match, the highest-priority action wins: block > redact > prompt > log_only.
Create a rule
Section titled “Create a rule”POST /api/admin/dlp-rules/Creates a rule and writes a version record with change_type: "create".
Request body
{ "detector_name": "Credit Card Detector", "detector_type": "regex", "entity_type": "credit_card", "action_tier": "redact", "enabled": true, "confidence_threshold": 0.5, "config_json": { "pattern": "\\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13})\\b" }}Fields
| Field | Type | Required | Description |
|---|---|---|---|
detector_name | string | yes | Human-readable rule name |
detector_type | string | yes | "regex", "ner", or "llm" |
entity_type | string | yes | Classification label (e.g. "credit_card", "ssn", "api_key") |
action_tier | string | yes | "log_only", "redact", "prompt", or "block" |
enabled | bool | no | Default true |
confidence_threshold | float | no | Minimum score to trigger (0.0–1.0, default 0.5) |
config_json | object | no | Detector-specific config (see below) |
config_json by detector type
Regex
{ "pattern": "<RE2-compatible regex>" }NER (Presidio)
{ "entities": ["PERSON", "EMAIL_ADDRESS", "PHONE_NUMBER"] }Entity labels must match Presidio recogniser names. If omitted, all supported entity types are scanned.
DeBERTa (llm)
{ "labels": ["api_key", "internal_credential"], "threshold": 0.75}Response 201 Created
{ "id": "rule-uuid-...", "detector_name": "Credit Card Detector", "detector_type": "regex", "entity_type": "credit_card", "action_tier": "redact", "enabled": true, "confidence_threshold": 0.5, "config_json": { "pattern": "..." }}List rules
Section titled “List rules”GET /api/admin/dlp-rules/Query parameters
| Parameter | Type | Description |
|---|---|---|
enabled | bool | Filter by enabled status |
detector_type | string | Filter by "regex", "ner", or "llm" |
Response 200 OK — array of rule objects.
Get a rule
Section titled “Get a rule”GET /api/admin/dlp-rules/{rule_id}Response 200 OK — single rule object.
Update a rule
Section titled “Update a rule”PUT /api/admin/dlp-rules/{rule_id}Partial update — only provided fields are modified. Writes a version record with change_type: "update".
Request body (all fields optional)
{ "action_tier": "block", "enabled": false}Response 200 OK
Delete a rule
Section titled “Delete a rule”DELETE /api/admin/dlp-rules/{rule_id}Soft-delete via version record with change_type: "delete", then hard-deletes the row. Returns 204 No Content.
Bulk export and import
Section titled “Bulk export and import”Export rules
Section titled “Export rules”GET /api/admin/dlp-rules/exportExports all tenant rules as a portable JSON envelope. Use this to back up custom rules or migrate between environments.
Response 200 OK
{ "version": "1.0", "exported_at": "2026-03-12T14:00:00Z", "tenant_id": "tenant-uuid-...", "rules": [ { "detector_name": "...", "detector_type": "regex", "entity_type": "...", "action_tier": "redact", "enabled": true, "confidence_threshold": 0.5, "config_json": { ... } } ]}Import rules
Section titled “Import rules”POST /api/admin/dlp-rules/importImports rules from a previously exported envelope with configurable conflict resolution.
Request body
{ "rules": [...], "conflict_mode": "skip"}conflict_mode | Behaviour on name conflict |
|---|---|
skip | Leave existing rule unchanged, record as skipped |
overwrite | Replace existing rule with imported values |
rename | Import as a new rule with a _imported suffix |
Response 200 OK
{ "imported": 5, "skipped": 2, "errors": [], "rules": [...]}Pattern testing (dry-run)
Section titled “Pattern testing (dry-run)”Test a single pattern
Section titled “Test a single pattern”POST /api/admin/dlp-rules/testTests a pattern against sample text without creating a rule. Safe for iterative regex development.
Request body
{ "rule_type": "regex", "pattern": "\\b[A-Z]{2}[0-9]{6}[A-Z]\\b", "sample_text": "Passport number AB123456C was found in the document."}rule_type | pattern interpretation |
|---|---|
regex | RE2-compatible regex string |
ner | Comma-separated Presidio entity labels (e.g. "PERSON,EMAIL_ADDRESS") |
gliner | Comma-separated zero-shot labels (e.g. "passport number,national id") |
Response 200 OK
{ "matches": [ { "start": 16, "end": 25, "matched_text": "AB123456C", "entity_type": null, "action": "log_only" } ], "match_count": 1, "rule_type": "regex", "valid_pattern": true, "error": null}If the pattern is invalid: valid_pattern: false with error describing the compilation failure. The regex engine uses safe_compile with a timeout guard to prevent ReDoS.
Full-chain evaluation
Section titled “Full-chain evaluation”Evaluate text against all active rules
Section titled “Evaluate text against all active rules”POST /api/admin/dlp-rules/evaluateSimulates the full DLP evaluation pipeline for a given organisation context. Useful for debugging unexpected allow/block decisions across the entire rule set.
The evaluation sequence:
- Load all enabled platform-level rules (global + tenant-scoped)
- Load org customisations (suppressions and custom patterns)
- Filter out platform rules suppressed by the org
- Evaluate remaining platform rules (regex → NER → DeBERTa)
- Evaluate org custom regex patterns
- Determine final action (highest-priority match wins)
Request body
{ "text": "Here is my SSN: 123-45-6789 and card number 4111-1111-1111-1111.", "org_id": "org-uuid-...", "group_id": null, "user_id": null}Response 200 OK
{ "text_length": 65, "org_id": "org-uuid-...", "rules_evaluated": 42, "rules_matched": 2, "final_action": "redact", "matched_rules": [ { "rule_id": "rule-uuid-a", "rule_name": "SSN Detector", "detector_type": "regex", "entity_type": "ssn", "action_tier": "redact", "match_count": 1, "matches": [ { "start": 16, "end": 27, "matched_text": "123-45-6789", "entity_type": null, "action": "redact" } ], "source": "platform" }, { "rule_id": "rule-uuid-b", "rule_name": "Credit Card Detector", "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=org-uuid-..., text_length=65", "Loaded 40 enabled platform rules", "Loaded 0 active org rules", "Platform rule evaluation complete: 40 evaluated, 2 matched", "Final action determined: redact" ]}Each matched_rules entry caps matches at 20 to avoid large payloads. The decision_trace array provides a step-by-step log of the evaluation for debugging.
Built-in pattern library
Section titled “Built-in pattern library”List available patterns
Section titled “List available patterns”GET /api/admin/dlp-rules/available-patternsReturns the built-in pattern library grouped by category. Use this to discover patterns available for quick rule creation.
Query parameters
| Parameter | Description |
|---|---|
category | Filter by category: "secret", "pii", "financial", "medical", "infrastructure" |
Response 200 OK
{ "total_patterns": 47, "categories": { "pii": [ { "name": "US Social Security Number", "entity_type": "ssn", "confidence_threshold": 0.9, "action_tier": "redact", "category": "pii" } ], "financial": [...], "secret": [...], "medical": [...], "infrastructure": [...] }}Version history
Section titled “Version history”Get rule version history
Section titled “Get rule version history”GET /api/admin/dlp-rules/{rule_id}/versionsReturns the full change history for a rule, ordered newest-first.
Response 200 OK
[ { "id": "version-uuid-...", "rule_id": "rule-uuid-...", "changed_by": "admin-user-uuid-...", "change_type": "update", "old_values": { "action_tier": "log_only" }, "new_values": { "action_tier": "redact" }, "changed_at": "2026-03-12T10:30:00Z" }]change_type | Description |
|---|---|
create | Rule was created; old_values is null |
update | Rule was modified; both old_values and new_values present |
delete | Rule was deleted; new_values is null |
Error codes
Section titled “Error codes”| Status | Meaning |
|---|---|
400 Bad Request | Invalid regex pattern or malformed request body |
403 Forbidden | Caller is not an admin |
404 Not Found | Rule ID does not exist within the tenant |
409 Conflict | Import name conflict when conflict_mode: "skip" is used |