PII Scrubbing API
PII Scrubbing replaces personally identifiable information — names, emails, phone numbers, SSNs, credit cards, IP addresses — with reversible tokens or redaction markers, in a single API call.
What is it?
PII Scrubbing replaces personally identifiable information — names, emails, phone numbers, SSNs, credit cards, IP addresses — with reversible tokens or redaction markers, in a single API call. It accepts a single JSON payload and returns a structured response in milliseconds — no agents, plugins, or background workers required. The API is designed for synchronous, real-time use: call it inline in your request handler, CI step, or event pipeline and act on the result immediately.
Why do you need it?
Problem
- PII ends up in application logs constantly — user emails in auth logs, phone numbers in SMS delivery logs, IP addresses in access logs — often without any engineer noticing.
- Analytics pipelines ingest raw event payloads from the frontend that contain user-entered form data, including names, addresses, and payment details.
- Support tickets and error reports routed to third-party tools like Zendesk or Sentry contain full PII because engineers copy-paste request bodies into tickets without sanitizing.
Consequence
- GDPR fines reach 4% of annual global revenue or €20M — whichever is higher. A single audit finding that PII was retained in logs beyond its legal basis can trigger a full investigation.
- CCPA breach notification requirements apply to any unauthorized access to personal data — a compromised log aggregator counts as a breach even if no production database was touched.
- Loss of customer trust from a PII exposure is hard to quantify but measurable: enterprise deals stall, SOC 2 audits flag the issue, and churn increases in the 6 months following a disclosed incident.
Solution
- Automated, deterministic scrubbing at ingestion time — PII is removed before data reaches your log aggregator, analytics platform, or third-party tool.
- Reversible tokenization lets you restore original values server-side for authorized lookups while everything downstream sees only tokens.
- Covers 20+ PII categories including GDPR Article 4 personal data, CCPA personal information, and HIPAA protected health information in a single call.
Use cases
Support ticket scrubbing
Scrub PII from support tickets before routing them to a third-party helpdesk like Zendesk or Freshdesk, so your customer data never leaves your security boundary.
Node.js — scrub before helpdesk
const API_KEY = process.env.DEVOPSIL_API_KEY;
const result = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: ticketBody,
mode: 'redact', // or 'tokenize' for reversibility
categories: ['email', 'phone', 'full_name', 'credit_card'],
}),
}).then(r => r.json());
await createZendeskTicket(result.scrubbed_text);result.scrubbed_text is safe for third-party storage. result.entities lists what was found and where.
Log pipeline PII removal
Strip PII from log lines before indexing in Elasticsearch or Datadog, keeping your log data useful for debugging while eliminating personal data.
Node.js — log pipeline scrub
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function scrubLogBatch(logLines: string[]) {
const result = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: logLines.join('\n'),
mode: 'redact',
}),
}).then(r => r.json());
return result.scrubbed_text.split('\n');
}Index result.scrubbed_text lines. Use result.entity_count for a scrub effectiveness metric in your data governance dashboard.
Analytics event scrubbing
Strip PII from analytics event payloads before sending to Mixpanel, Segment, or Amplitude so your analytics vendor never receives personal data.
Node.js — strip PII from event
const API_KEY = process.env.DEVOPSIL_API_KEY;
async function trackEvent(event: Record<string, unknown>) {
const serialized = JSON.stringify(event);
const result = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: serialized, mode: 'redact' }),
}).then(r => r.json());
const cleanEvent = JSON.parse(result.scrubbed_text);
await mixpanel.track(event.name, cleanEvent);
}Send cleanEvent to your analytics vendor. It contains the same structure but with PII replaced by [REDACTED] markers.
LLM input/output scrubbing
Remove PII before sending user text to an AI API (OpenAI, Anthropic, etc.) and optionally restore tokens in the AI's response if the context requires original values.
Node.js — LLM PII scrub/restore
const API_KEY = process.env.DEVOPSIL_API_KEY;
// Scrub user input before sending to AI
const scrubResult = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: userMessage, mode: 'tokenize' }),
}).then(r => r.json());
const aiResponse = await callOpenAI(scrubResult.scrubbed_text);
// Restore tokens in AI response for display to the original user
const restoreResult = await fetch('https://devopsil.com/api/v1/pii/restore', {
method: 'POST',
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: aiResponse, token_map: scrubResult.token_map }),
}).then(r => r.json());Display restoreResult.restored_text to the user. The AI never saw real PII; the user sees a coherent response with their original values.
Database migration prep
Scrub a production data dump before loading it into a staging or development environment, so developers can test with realistic data shapes without real PII.
Node.js — scrub DB dump
const API_KEY = process.env.DEVOPSIL_API_KEY;
const fs = require('fs');
const dump = fs.readFileSync('prod_dump.sql', 'utf8');
// Process in chunks to stay under 1MB limit
for (const chunk of splitIntoChunks(dump, 900_000)) {
const result = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: chunk, mode: 'redact' }),
}).then(r => r.json());
fs.appendFileSync('staging_dump.sql', result.scrubbed_text);
}Load staging_dump.sql into your dev DB. All PII is replaced with consistent redaction markers — email@[REDACTED].com format preserves structure.
Error report scrubbing
Strip PII from exception stack traces and request bodies before sending to Sentry or Bugsnag, so your error tracking tool never ingests personal data.
Node.js — Sentry beforeSend hook
const API_KEY = process.env.DEVOPSIL_API_KEY;
// In your Sentry init config
Sentry.init({
beforeSend: async (event) => {
const raw = JSON.stringify(event);
const result = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: raw, mode: 'redact' }),
}).then(r => r.json());
return JSON.parse(result.scrubbed_text);
},
});Sentry receives a clean event. Error messages and request bodies are scrubbed; the stack trace structure is preserved for debugging.
PII categories detected
| Category | Examples | Default action |
|---|---|---|
| Full name | "John Smith", "María García" | Redact |
| Email address | [email protected] | Redact |
| Phone number | +1-555-123-4567, (555) 123-4567 | Redact |
| SSN / NIN | 123-45-6789, AB 123456 C | Redact |
| Credit card number | 4111 1111 1111 1111 | Redact |
| IP address | 192.168.1.1, 2001:db8::1 | Redact |
| Passport number | A12345678 | Redact |
| Date of birth | 1990-03-15, March 15, 1990 | Redact |
| Physical address | "123 Main St, Springfield" | Redact |
How the API works
All requests use Bearer authentication. Your API key starts with pii_. Get one at /dashboard/api-keys.
Request
{
"text": "Contact Alice Johnson at [email protected] or call +1-415-555-0192. Her SSN is 123-45-6789.",
"mode": "redact",
"categories": ["full_name", "email", "phone", "ssn"]
}Response
{
"scrub_id": "scr_7pq3mz9a",
"scrubbed_text": "Contact [NAME] at [EMAIL] or call [PHONE]. Her SSN is [SSN].",
"entities": [
{ "type": "full_name", "original": "Alice Johnson", "position": [8, 21], "confidence": 0.97 },
{ "type": "email", "original": "[email protected]", "position": [25, 47], "confidence": 0.99 },
{ "type": "phone", "original": "+1-415-555-0192", "position": [57, 73], "confidence": 0.98 },
{ "type": "ssn", "original": "123-45-6789", "position": [83, 94], "confidence": 0.99 }
],
"entity_count": 4,
"mode": "redact",
"processing_ms": 22
}Quick start
Get your API key
Create a free account and generate a key at /dashboard/api-keys. Your key starts with pii_.
Make your first call
Node.js
const API_KEY = process.env.DEVOPSIL_API_KEY; // starts with pii_
const result = await fetch('https://devopsil.com/api/v1/pii/scrub', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: 'Call Alice at [email protected] or 555-123-4567.',
mode: 'redact',
}),
}).then(r => r.json());
console.log(result.scrubbed_text);
// "Call [NAME] at [EMAIL] or [PHONE]."Act on the result
Node.js — handle response
if (result.entity_count > 0) {
// Use the scrubbed version for storage / forwarding
await storeOrForward(result.scrubbed_text);
console.log(`Scrubbed ${result.entity_count} PII entities in ${result.processing_ms}ms`);
} else {
// No PII found — safe to use original
await storeOrForward(originalText);
}