Skip to content

DLP Rules API

The DLP Rules API manages the detection rules that power the five-tier DLP pipeline. All endpoints are admin-only (Authorization: Bearer <admin-token>).

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_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.


POST /api/v1/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": "..." }
}

GET /api/v1/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 /api/v1/admin/dlp-rules/{rule_id}

Response 200 OK — single rule object.


PUT /api/v1/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 /api/v1/admin/dlp-rules/{rule_id}

Soft-delete via version record with change_type: "delete", then hard-deletes the row. Returns 204 No Content.


GET /api/v1/admin/dlp-rules/export

Exports 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": { ... }
}
]
}

POST /api/v1/admin/dlp-rules/import

Imports 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": [...]
}

POST /api/v1/admin/dlp-rules/test

Tests 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.


POST /api/v1/admin/dlp-rules/evaluate

Simulates 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:

  1. Load all enabled platform-level rules (global + tenant-scoped)
  2. Load org customisations (suppressions and custom patterns)
  3. Filter out platform rules suppressed by the org
  4. Evaluate remaining platform rules (regex → NER → DeBERTa)
  5. Evaluate org custom regex patterns
  6. 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.


GET /api/v1/admin/dlp-rules/available-patterns

Returns 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": [...]
}
}

GET /api/v1/admin/dlp-rules/{rule_id}/versions

Returns 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

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