Open in the interactive docs · markdown for agents: https://neuraldeep.tech/docs/guardrails.md
PII anonymization · PII Guard API
With the same key you can anonymize personal data (PII) under /v1/pii/*. The service finds PII in Russian text, replaces it with tags like <PII type="PERSON" gender="male" id="1" />, and on the way back puts the originals back with the right Russian grammatical case for names and places. It runs on our GPU in Russia.
Two ways to use it:
- your own pipeline: call
/anonymizeand/deanonymizeyourself, as in the examples below; - shield on a key: turned on in the dashboard, under "Keys", with the PII-Guard switch. After that every chat request with that key is anonymized before the model and the answer is restored before the client. Cursor, opencode, Open WebUI, n8n and any OpenAI-compatible client work with no code changes. Only chat requests are covered: embeddings, rerank, audio and images are not.
What it finds. 25 types: PERSON, LOCATION, EMAIL_ADDRESS, PHONE_NUMBER, URL, IP_ADDRESS, IP_PORT, DATE_TIME, PASSPORT, CREDIT_CARD, CVC, DRIVER_LICENSE, INN, KPP, OGRN, OGRNIP, SNILS, MILITARY_ID, BIRTH_CERTIFICATE, OMS, BANK_ACCOUNT, BIK, POSTAL_CODE, TELEGRAM, TOKEN (access keys and tokens). You can list them in entities; old names like FIRST_NAME, CITY, PHONE, EMAIL are accepted too. An unknown type returns 422 with the list of known ones. Documents with a checksum (INN, SNILS, cards, accounts, BIK) are caught by rules that verify the checksum; names, places, phones and links are found by a ruBERT-based neural network fine-tuned on Russian PII. Detection is probabilistic: it cuts the risk of a leak a lot, but does not guarantee it catches everything.
Privacy. We don't store texts. The tag → original mapping is returned to you in the /anonymize response and deleted on our side right away. You keep it and send it back in /deanonymize. To count repeats (see pricing) we keep only a hash of the text for one hour; the text can't be recovered from it.
Endpoints:
POST /v1/pii/anonymize:{text}or{texts:[…]}, optionallyentities(a list of types if you only need some, e.g.["PERSON","PHONE_NUMBER"]). Response:{anonymized, mapping, action, quota}.anonymizedis a string fortextand an array fortexts;actionisANONYMIZEif something was found andNONEotherwise.POST /v1/pii/deanonymize:{text|texts, mapping}→{deanonymized, quota}.GET /v1/pii/quota: what's left of the subscription quota for the day and month. When it runs out you get429withRetry-After.
Batching. texts takes up to 512 texts per call, each up to 1M characters. The response keeps the request order.
Agent sessions. An agent resends the whole history on every step. Send each message as a separate string in texts: messages this account already sent within the last hour count as cached input and cost 10× less, and you don't pay for their output. The key shield does this on its own.
Speed. A short text takes tens of milliseconds; a 1M-character document about 4 seconds the first time and about 0.5 seconds on repeat.
🎁 Anonymization is free for everyone until October 20 inclusive: neither the API nor the key shield charges anything, no balance is needed, and subscription quotas are raised to the Pro level for this period. The prices below apply from October 21.
Pricing. Per token, like the models: you pay for input and output even if no PII was found, because the GPU did the work anyway. Tokens are estimated from length: about 2.3 characters of Russian text per token.
| what | ₽ per 1M tokens |
|---|---|
| anonymization, input | 5 |
| anonymization, output | 5 |
| cached input (text you already sent within the hour) | 0.5 |
| restoration, input and output | 1 and 1 |
Example. An agent with a 300k-character history (about 130k tokens). The first step costs about 1.3 ₽ for anonymization. The next step with the same history plus a new 2k-character message costs about 7 kopecks: the history comes from the cache, you mostly pay for the new message.
From the wallet there's no cap, billing follows the table above. On a subscription anonymization is included in the plan with a token quota per day and month, where cached input counts as one tenth. The key shield has its own spending caps per request and per day; you can see and change them in the dashboard.
# 1. anonymize, keep the mapping from the response
curl https://api.neuraldeep.tech/v1/pii/anonymize \
-H "Authorization: Bearer $YOUR_KEY" -H "Content-Type: application/json" \
-d '{"text":"Иван Петров, +79161234567, живёт в Москве"}'
# → {"anonymized":"<PII type=\"PERSON\" gender=\"male\" id=\"1\" />, <PII type=\"PHONE_NUMBER\" id=\"2\" />, ...",
# "mapping":{"<PII type=\"PERSON\" gender=\"male\" id=\"1\" />":"Иван Петров", ...}, "action":"ANONYMIZE", "quota":{...}}
# 2. restore the model's answer: tags → originals, with inflection
curl https://api.neuraldeep.tech/v1/pii/deanonymize \
-H "Authorization: Bearer $YOUR_KEY" -H "Content-Type: application/json" \
-d '{"text":"Письмо для <PII type=\"PERSON\" gender=\"male\" id=\"1\" />","mapping":{...}}'
import httpx
H = {"Authorization": "Bearer $YOUR_KEY"}
API = "https://api.neuraldeep.tech/v1"
# 1. anonymize the user's text
a = httpx.post(f"{API}/pii/anonymize", headers=H,
json={"text": "Иван Петров, тел +79161234567, Москва"}).json()
safe, mapping = a["anonymized"], a["mapping"]
# 2. send to ANY model without PII, ask it to keep the tags
resp = httpx.post(f"{API}/chat/completions", headers=H, json={
"model": "qwen3.6-35b-a3b",
"messages": [{"role": "system", "content": "Keep <PII .../> tags in your answer exactly as they are; don't change or reveal them."},
{"role": "user", "content": safe}],
}).json()["choices"][0]["message"]["content"]
# 3. restore the PII in the model's answer with the same mapping
final = httpx.post(f"{API}/pii/deanonymize", headers=H,
json={"text": resp, "mapping": mapping}).json()["deanonymized"]
print(final)
history = ["Привет, я Иван Петров", "Здравствуйте! Чем помочь?", "Мой ИНН 7707083893"]
a = httpx.post(f"{API}/pii/anonymize", headers=H, json={"texts": history}).json()
safe_history = a["anonymized"] # array in the same order
# on the next step send the same history + the new message:
# the first three strings count as cached input
Reference sections (markdown for agents)
- Start · key, errors, quotas
- Text · chat
- Vectorization
- Reranking
- Transcription
- Image recognition
- Structured output
- Clients · agents
- Remaining limits · Limits API
- Search · Search API
- OCR · documents
- Images · Image API
- Music · Music API
- PII anonymization · PII Guard
- SpeechCore · STT
- Speech synthesis · TTS API
- Who spoke when · diarization
- Text decisions · FRIDA-Decisions, clef-flash
- Drift · overview
- Files + sandbox preview
- Your own tools, skills, MCP
- Tasks · proactive
- Memory · memory
- Isolation and security
- Agent settings
- Limits · errors
- Book · search and MCP
- Streaming
- SDK · Python / JS
- Privacy