How to Strip PII from LLM Prompts with One API Call
Source: Dev.to
Introduction
Building an AI app that processes sensitive user data—such as medical records—requires a way to remove personally identifiable information (PII) before sending the prompt to a large language model (LLM). Sending protected health information (PHI) or other confidential data directly to services like OpenAI or Claude can create compliance issues (HIPAA, GDPR, PCI, etc.).
This guide shows how to automatically scrub PII with a single API call, then safely forward the sanitized text to any LLM.
Why a privacy proxy?
- Compliance – Prevent raw PII from reaching external LLM providers.
- Speed – Scrubbing takes ~42 ms, far faster than building a custom NER pipeline.
- Cost – $0.001 per request (free tier: 50 scrub requests/day).
- Accuracy – 97 % entity detection on a 10 K+ medical‑record test set (spaCy + Presidio).
- Coverage – Detects 15+ entity types: names, emails, phones, SSNs, credit cards, IPs, dates, medical codes, drug names, addresses, URLs, API keys, crypto addresses, etc.
How it works
- Send raw text to the
/api/scrubendpoint. - The service returns:
scrubbed– the original text with PII replaced by placeholders like[NAME_1].entities– a map of placeholder keys to the original values.
- Forward the scrubbed text to your LLM of choice.
- (Optional) Re‑inject entities into the LLM response for UI display.
Example API call
curl -X POST https://tiamat.live/api/scrub \
-H "Content-Type: application/json" \
-d '{
"text": "Patient John Smith (SSN: 123-45-6789) was diagnosed with Type 2 diabetes on 2023-01-15. His doctor is Dr. Alice Chen at massachusetts-general-hospital.org."
}'
Response
{
"scrubbed": "Patient [NAME_1] (SSN: [SSN_1]) was diagnosed with Type 2 diabetes on [DATE_1]. His doctor is [TITLE_1] [NAME_2] at [ORG_1].",
"entities": {
"NAME_1": "John Smith",
"SSN_1": "123-45-6789",
"DATE_1": "2023-01-15",
"TITLE_1": "Dr.",
"NAME_2": "Alice Chen",
"ORG_1": "massachusetts-general-hospital.org"
}
}
Python integration
import requests
user_input = "My name is Sarah and my account number is ACC-12345-XYZ. Please summarize my medical records."
# Step 1: Scrub PII
scrub_resp = requests.post(
"https://tiamat.live/api/scrub",
json={"text": user_input}
)
scrub_data = scrub_resp.json()
scrubbed = scrub_data["scrubbed"]
entities = scrub_data["entities"]
print("Scrubbed:", scrubbed)
# → "My name is [NAME_1] and my account number is [ACCOUNT_1]. Please summarize my medical records."
# Step 2: Send to Claude (or any LLM)
llm_resp = requests.post(
"https://api.anthropic.com/v1/messages",
headers={"x-api-key": "your-claude-key"},
json={
"model": "claude-3-5-sonnet-20241022",
"messages": [{"role": "user", "content": scrubbed}]
}
)
response_text = llm_resp.json()["content"][0]["text"]
print("Claude response:", response_text)
# Optional: Restore entities for UI
ui_response = response_text
for key, value in entities.items():
ui_response = ui_response.replace(f"[{key}]", value)
print("UI response:", ui_response)
JavaScript (Fetch API) integration
// Scrub request
const scrubResp = await fetch('https://tiamat.live/api/scrub', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: 'My email is john@example.com and my phone is 555-123-4567' })
});
const scrubData = await scrubResp.json();
console.log(scrubData.scrubbed); // "My email is [EMAIL_1] and my phone is [PHONE_1]"
// Using the scrubbed text with an LLM (example placeholder)
const llmResp = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your-claude-key'
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
messages: [{ role: 'user', content: scrubData.scrubbed }]
})
});
const llmData = await llmResp.json();
console.log(llmData.content[0].text);
Pricing & limits
| Tier | Daily scrub requests | Cost per request | Payment method |
|---|---|---|---|
| Free | 50 | $0.001 (free) | — |
| Paid | Unlimited | $0.001 | USDC on Base network |
No credit‑card required for the free tier. Upgrade when you exceed the free quota.
API reference
Endpoint: https://tiamat.live/api/scrub
Request (JSON)
{
"text": "string (required) — text to scrub"
}
Successful response
{
"scrubbed": "string — text with PII replaced by [TYPE_N] placeholders",
"entities": {
"[NAME_1]": "John Smith",
"[EMAIL_1]": "john@example.com"
// …
}
}
Error response
{
"error": "Rate limit exceeded",
"error_code": "RATE_LIMITED",
"retry_after": 3600 // seconds until next allowed request
}
Best practices
- Validate the
entitiesmap to ensure all placeholders were correctly replaced before showing the response to users. - Monitor rate limits using the
retry_afterfield in error responses. - Log only the scrubbed text (never the raw PII) if you need audit trails.
- Combine with additional security layers (TLS, authentication) when integrating into production systems.
Conclusion
PII scrubbing no longer needs a multi‑month engineering effort. With a single API call you can:
- Remove sensitive data in memory.
- Preserve the original values for later re‑insertion.
- Keep compliance (HIPAA, GDPR, PCI) while leveraging powerful LLMs.
Try the free tier at and integrate the two‑line scrub call into your app today.