Skip to main content

DLP — Data Patterns

Manage Data Patterns on the DLP service (/v2/api/data-patterns).

Subclient lives at client.dlp.dataPatterns (a DataPatternsClient). Full CRUD: list, create, get, replace (PUT), patch (RFC 7396 JSON Merge Patch), delete. DELETE soft-deletes (archives) server-side — the pattern becomes invisible to list but its id still resolves on get() with status: 'deleted'.

Spec source: openapi-specs/dlp/DataPatterns.yaml in the public pan.dev repository, read through the SDK's gitignored schemas/ alias (see API Design & Versioning).

How it works​

A data pattern is the lowest-level building block in DLP: a single, reusable detector. It says "here is what sensitive data looks like" — a set of regexes, proximity keywords, or another detection technique (regex, weighted_regex, dictionary, edm, ml, fingerprinting, etc.). A pattern on its own does nothing; it has to be referenced by a data profile to take effect.

Where it sits among the four DLP resources:

ResourceRole
Data Patterns (this one)The detectors — regex / keyword / technique that recognize data
DictionariesKeyword lists a pattern can reference via the dictionary technique
Data ProfilesBundle patterns (and dictionaries) into a detection policy with AND/OR logic
Data Filtering ProfilesApply a data profile to actually filter/block matching content

Flow: pattern → referenced by a data profile → bound to a data filtering profile → enforced on traffic. Patterns are the leaves; everything else composes them upward. Palo Alto ships dozens of predefined patterns (SSN, credit cards, AWS keys, …) you can reference without authoring anything — create custom patterns only when the built-ins miss your data.

Get the most out of it​

  • Prefer weighted_regex with proximity keywords over bare regex for anything that looks like a common number sequence. A raw 16-digit run matches phone systems, order IDs, and SKUs; the same run within proximity_distance of "card" / "visa" scores high and stays quiet otherwise. Weighting is how you trade false positives for confidence levels.
  • Set supported_confidence_levels deliberately. Data profiles select a confidence_level per rule item; a pattern only offers the levels you list here. If you forget high, profiles can't require high-confidence hits from this pattern.
  • Check for a predefined pattern first. Authoring a custom credit-card regex when a maintained predefined one exists means you now own its accuracy forever.
  • Tag for auditability. tags.classification / compliance / geography are free-text aids for filtering and reporting later — fill them in (PCI, PCI-DSS-3.2.1, EU) so compliance audits can slice by them.
  • Gotcha — escape regexes for JSON. \b\d{16}\b becomes '\\b\\d{16}\\b' in a TS/JSON string. A lost backslash silently changes what matches.
  • Gotcha — Merge Patch replaces arrays wholesale. Patching matching_rules does not merge into the existing regex list; re-send the full set (see Use case 2).
  • Gotcha — DELETE is a soft-delete. The pattern disappears from list() but its id still resolves on get() as status: 'deleted'; reusing the name later may collide.

Setup​

import { ManagementClient } from '@cdot65/prisma-airs-sdk';

const client = new ManagementClient();

Required fields​

FieldTypeRequired on POSTRequired on PATCHNotes
namestring (1..64)✅✅Spec enforces length bounds
type'predefined' | 'custom' | 'file_property'✅✅custom for tenant-authored patterns
detection_config{ technique, supported_confidence_levels? }✅✅Required even on patch
matching_rulesDataPatternMatchingRules—nullableregexes, proximity keywords, metadata criteria
tagsDataPatternTags—nullableclassification, compliance, geography
descriptionstring—nullableOmit to leave unchanged on patch; null to clear

Detection techniques (the detection_config.technique enum): edm, document_fingerprint, trainable_classifier, ml_document, regex, weighted_regex, ml, titus_tag, wildfire, file_property, dictionary, pab, document_classifier.

Schema source: src/models/dlp-data-pattern.ts.

API reference​

list​

const page = await client.dlp.dataPatterns.list({
page: 0,
size: 20,
sort: ['name,asc', 'id,desc'],
});
for (const p of page.content) console.log(p.id, p.name);

const allPatterns = await client.dlp.dataPatterns.listAll({
size: 100,
sort: ['name,asc'],
});

listAll() combines every Spring page into one array and preserves list filters. Collection is capped at 10,000 records by default; pass max: 0 for an intentional unbounded walk.

create​

name, type, and detection_config are required.

const created = await client.dlp.dataPatterns.create({
name: 'cc-numbers-strict',
type: 'custom',
detection_config: { technique: 'regex' },
matching_rules: {
regexes: [{ regex: '\\b\\d{16}\\b', weight: 1.0 }],
},
});
console.log(created.id);

get​

const pattern = await client.dlp.dataPatterns.get('pat-001');

replace​

Full PUT.

const replaced = await client.dlp.dataPatterns.replace('pat-001', {
name: 'cc-numbers-strict',
type: 'custom',
detection_config: { technique: 'regex' },
matching_rules: {
regexes: [{ regex: '\\b\\d{15,16}\\b', weight: 1.0 }],
},
});

patch​

JSON Merge Patch. name, type, and detection_config are required even on patch. Other fields use nullable semantics — omit to leave unchanged, send null to clear.

const patched = await client.dlp.dataPatterns.patch('pat-001', {
name: 'cc-numbers-strict-v2',
type: 'custom',
detection_config: { technique: 'regex' },
description: null,
});

delete​

204 No Content. Returns void. Soft-deletes server-side.

await client.dlp.dataPatterns.delete('pat-001');

Use cases​

Use case 1 — Create a weighted credit-card detector and validate its post-create state​

Scenario. Build a custom pattern that detects 15- or 16-digit credit-card-like sequences with proximity to keywords like "card", "visa", "mastercard". Weighted regexes let the engine score matches by confidence — a bare 16-digit run scores low, the same run within 30 chars of "card number" scores high.

Input.

import { ManagementClient } from '@cdot65/prisma-airs-sdk';

const client = new ManagementClient();

const created = await client.dlp.dataPatterns.create({
name: 'cc-numbers-weighted',
type: 'custom',
description: 'Credit-card numbers, weighted by proximity to card-related keywords',
detection_config: {
technique: 'weighted_regex',
supported_confidence_levels: ['low', 'medium', 'high'],
},
matching_rules: {
proximity_distance: 30,
proximity_keywords: ['card', 'credit', 'visa', 'mastercard', 'amex'],
regexes: [
{ regex: '\\b\\d{16}\\b', weight: 1.0 },
{ regex: '\\b\\d{15}\\b', weight: 0.8 }, // amex is 15
],
},
tags: {
classification: ['PCI'],
compliance: ['PCI-DSS-3.2.1'],
geography: ['US', 'EU'],
},
});

Expected output. POST returns DataPatternResponse — the API generates id, status, version, and audit_metadata:

{
"id": "pat-7c4a91",
"name": "cc-numbers-weighted",
"description": "Credit-card numbers, weighted by proximity to card-related keywords",
"tenant_id": "tnt-001",
"type": "custom",
"status": "active",
"license_type": "standard",
"version": 1,
"detection_config": {
"technique": "weighted_regex",
"supported_confidence_levels": ["low", "medium", "high"]
},
"matching_rules": {
"proximity_distance": 30,
"proximity_keywords": ["card", "credit", "visa", "mastercard", "amex"],
"regexes": [
{ "regex": "\\b\\d{16}\\b", "weight": 1.0 },
{ "regex": "\\b\\d{15}\\b", "weight": 0.8 }
]
},
"tags": {
"classification": ["PCI"],
"compliance": ["PCI-DSS-3.2.1"],
"geography": ["US", "EU"]
},
"audit_metadata": {
"created_at": "2026-05-23T17:11:02Z",
"created_by": "ops@example.com"
}
}

Validation. Assert the server preserved the input shape and stamped the lifecycle fields:

if (!created.id) throw new Error('create() did not return an id');
if (created.status !== 'active') {
throw new Error(`new pattern not active: status=${created.status}`);
}
if (created.version !== 1) {
throw new Error(`expected version 1 for new pattern, got ${created.version}`);
}
if (created.detection_config?.technique !== 'weighted_regex') {
throw new Error(
`detection_config.technique not preserved: ${created.detection_config?.technique}`,
);
}
const regexCount = created.matching_rules?.regexes?.length ?? 0;
if (regexCount !== 2) {
throw new Error(`expected 2 regexes round-tripped, got ${regexCount}`);
}
if (!created.tags?.compliance?.includes('PCI-DSS-3.2.1')) {
throw new Error('compliance tag not persisted');
}
console.log(`ok: pattern ${created.id} created (v${created.version})`);

Use case 2 — Patch an existing pattern to widen its regex and clear its description​

Scenario. The above cc-numbers-weighted is too strict — it misses 13-digit cards. JSON Merge Patch lets us update only matching_rules (re-sending it in full, since arrays/objects are replaced not merged in JSON Merge Patch) and simultaneously clear the description by sending description: null.

Input.

const id = 'pat-7c4a91';

const patched = await client.dlp.dataPatterns.patch(id, {
// Required even on patch:
name: 'cc-numbers-weighted',
type: 'custom',
detection_config: {
technique: 'weighted_regex',
supported_confidence_levels: ['low', 'medium', 'high'],
},
// Replace matching_rules entirely (Merge Patch replaces arrays wholesale):
matching_rules: {
proximity_distance: 30,
proximity_keywords: ['card', 'credit', 'visa', 'mastercard', 'amex'],
regexes: [
{ regex: '\\b\\d{16}\\b', weight: 1.0 },
{ regex: '\\b\\d{15}\\b', weight: 0.8 },
{ regex: '\\b\\d{13}\\b', weight: 0.6 },
],
},
// Clear the description:
description: null,
// Omit `tags` entirely to leave them unchanged.
});

Expected output. Same DataPatternResponse shape with version bumped, description cleared (the live API emits null, not an absent key, for unset values), and the third regex present:

{
"id": "pat-7c4a91",
"name": "cc-numbers-weighted",
"description": null,
"tenant_id": "tnt-001",
"type": "custom",
"status": "active",
"version": 2,
"detection_config": {
"technique": "weighted_regex",
"supported_confidence_levels": ["low", "medium", "high"]
},
"matching_rules": {
"proximity_distance": 30,
"proximity_keywords": ["card", "credit", "visa", "mastercard", "amex"],
"regexes": [
{ "regex": "\\b\\d{16}\\b", "weight": 1.0 },
{ "regex": "\\b\\d{15}\\b", "weight": 0.8 },
{ "regex": "\\b\\d{13}\\b", "weight": 0.6 }
]
},
"tags": {
"classification": ["PCI"],
"compliance": ["PCI-DSS-3.2.1"],
"geography": ["US", "EU"]
},
"audit_metadata": {
"created_at": "2026-05-23T17:11:02Z",
"created_by": "ops@example.com",
"updated_at": "2026-05-23T17:38:55Z",
"updated_by": "ops@example.com"
}
}

Validation. Assert the new regex landed, description was cleared, tags were left alone:

if (patched.id !== id) throw new Error(`id changed unexpectedly: ${patched.id}`);
if (patched.version == null || patched.version < 2) {
throw new Error(`version did not advance past 1: ${patched.version}`);
}
const regexes = patched.matching_rules?.regexes ?? [];
const hasThirteen = regexes.some((r) => r.regex.includes('{13}'));
if (!hasThirteen) {
throw new Error('13-digit regex was not persisted');
}
if (patched.description != null && patched.description !== '') {
throw new Error(`description not cleared: ${JSON.stringify(patched.description)}`);
}
// Tags were omitted from the PATCH body — server should have left them intact.
if (!patched.tags?.compliance?.includes('PCI-DSS-3.2.1')) {
throw new Error('tags were dropped — omitted fields should be preserved on Merge Patch');
}
console.log(`ok: patched to v${patched.version}, now matches ${regexes.length} regexes`);

Error handling​

DLP request bodies are typed (DataPatternRequest, DataPatternPatchRequest) but are not parsed locally before the request is sent — the exported Zod request schemas are available for you to call .parse() on if you accept external input. An invalid body (for example an empty name) is rejected by the DLP API and surfaces as a CLIENT_SIDE_ERROR with the 4xx statusCode:

import { AISecSDKException, DataPatternRequestSchema, ErrorType } from '@cdot65/prisma-airs-sdk';

const body = {
name: '', // violates the schema's min(1)
type: 'custom',
detection_config: { technique: 'regex' },
} as const;

// Optional: validate locally first (throws a ZodError, not an AISecSDKException).
const local = DataPatternRequestSchema.safeParse(body);
if (!local.success) console.error('rejected locally:', local.error.issues[0]?.message);

try {
await client.dlp.dataPatterns.create(body);
} catch (err) {
if (err instanceof AISecSDKException) {
if (err.errorType === ErrorType.CLIENT_SIDE_ERROR) {
console.error(`API rejected (${err.statusCode}):`, err.message);
} else if (err.errorType === ErrorType.OAUTH_ERROR) {
console.error('check PANW_MGMT_* env vars:', err.message);
} else {
console.error(err.errorType, err.message);
}
} else {
throw err;
}
}

See also​