zer0pii runs as a sanitizing gateway in front of your LLM provider. Any IDE, CLI or agent that lets you set a custom base URL and an API key can be routed through it without a plugin, a browser extension or any change to the tool itself.
The model in one paragraph
Your tool talks to zer0pii's gateway URL with a zer0pii key. The gateway masks personal data in the request (names, emails, phone numbers, national IDs, card numbers, credentials and more), forwards the masked request to the provider using your provider key, and reconstitutes the reply so the tool sees the original values. Nothing is retained: the mapping between masked tokens and real values lives only for the duration of the request, and every response carries a signed receipt saying so.
IDE / CLI --(zpii_ key)--> zer0pii gateway --(your provider key)--> OpenAI / Anthropic / Gemini
<-- reply with original values restored --
What you need
- A gateway URL. The hosted gateway is
https://api.zer0pii.com/v1(the default indocker-compose.yml). Self-hosted deployments use their own hostname; every guide below writes it ashttps://<your-gateway>/v1. - A zer0pii gateway key. Sign in to the console, open API keys (
/console/keys), click Issue key, and copy it: the plaintext is shown once. Keys start withzpii_and are sent asAuthorization: Bearer zpii_...(source:apps/gateway/core/auth.py,apps/gateway/api/v1/admin.py). - Your provider key. Either sent per request in the
X-zer0pii-Upstream-Keyheader, or configured once on the gateway by your admin (UPSTREAM_API_KEY,UPSTREAM_ANTHROPIC_API_KEY,UPSTREAM_GEMINI_API_KEYin.env; source:apps/gateway/core/providers.py). When the gateway holds the key, your tool only ever sees the zer0pii key.
The three routes
All three are served under the same /v1 prefix (source: apps/gateway/api/v1/proxy.py, apps/gateway/main.py).
| Route | Shape | Forwards to (default) | Provider auth the gateway sends |
|---|---|---|---|
POST /v1/chat/completions |
OpenAI Chat Completions | https://api.openai.com/v1 |
Authorization: Bearer <provider key> |
POST /v1/messages |
Anthropic Messages | https://api.anthropic.com/v1 |
x-api-key: <provider key> plus anthropic-version: 2023-06-01 |
POST /v1/models/{model}:generateContent and :streamGenerateContent |
Google Gemini | https://generativelanguage.googleapis.com/v1beta |
x-goog-api-key: <provider key> |
Streaming works on all three. Tool calls and tool results are masked and restored too.
Optional per-request headers (source: proxy.py):
X-zer0pii-Upstream-URL: send this request to a different provider endpoint (for example an OpenAI-compatible server your team runs). Must be a public hostname; private and internal addresses are refused.X-zer0pii-Conversation-ID: keeps masked tokens stable across the turns of one conversation so the provider's prompt cache keeps hitting. Without it, tokens are stable per organisation.X-zer0pii-Policy-Group:healthcare,clinical,financeorhrswitch the request to fail-closed behaviour and, for the clinical groups, date masking.
Embeddings: there is an embeddings route, but masking changes the vectors it returns, so it is not generally enabled. Ask your admin before pointing an embeddings workload at the gateway.
Which of my tools does this cover
The honest boundary: this path covers a tool only when it lets you set the base URL and give it a key you control. It does not and cannot cover a tool that authenticates with a subscription or OAuth login, because there is no key for the gateway to forward and the tool's traffic never passes through a URL you choose. Each "covered" row below was checked against the vendor's own documentation on the date shown; each "not covered" row is stated so you do not have to find out in production.
| Tool | Covered? | How | Verified against |
|---|---|---|---|
| Claude Code, API-key mode | Yes | ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN (see claude-code.md) |
code.claude.com/docs/en/llm-gateway-connect, read 2026-09-22 |
| Claude Code, claude.ai subscription login (Pro / Max / Team seat) | No | No key to proxy. Setting only ANTHROPIC_BASE_URL keeps the saved login as the active credential and the subscription's terms apply. Hooks cannot rewrite prompts or replies either. |
code.claude.com/docs/en/llm-gateway, "Subscriptions and gateways", read 2026-09-22 |
Continue (VS Code / JetBrains), provider: openai |
Yes | apiBase + apiKey in config.yaml (see continue.md) |
docs.continue.dev/customize/model-providers/top-level/openai, read 2026-09-22 |
Continue, provider: anthropic |
Partial | apiBase is listed as a general model field in the config reference but is not shown in the Anthropic provider page; documented here with that caveat |
docs.continue.dev/reference and .../top-level/anthropic, read 2026-09-22 |
| Cursor | Not verified | Cursor's current documentation describes custom API keys (Cursor Settings > Models) but does not document a base URL override, and states custom keys are sent through Cursor's backend. See cursor.md before assuming coverage. | cursor.com/docs/settings/api-keys and cursor.com/help/models-and-usage/api-keys, read 2026-09-22 |
| AWS Bedrock or Google Vertex as the upstream | Not today | The gateway forwards to the public OpenAI, Anthropic and Gemini APIs only. See bedrock-vertex.md. | apps/gateway/api/v1/proxy.py, core/providers.py |
| Any OpenAI SDK, Anthropic SDK or Gemini SDK client | Yes | Set the SDK's base URL to the gateway and its API key to your zpii_ key; pass X-zer0pii-Upstream-Key as a default header or let the gateway hold the provider key |
apps/gateway/api/v1/proxy.py |
| Any other IDE or CLI | Check | Covered if, and only if, it exposes both a base URL setting and an API key setting for the provider format it speaks. If it only offers "sign in", it is not covered. | Its own documentation |
Guides
- claude-code.md: Claude Code in API-key mode
- continue.md: Continue
- cursor.md: Cursor, with what is and is not documented
- bedrock-vertex.md: Bedrock and Vertex upstreams, status
- verify.md: the 60-second check that masking is actually happening
What the tool sees, and what it does not
- The tool sees the reply with real values restored. It never sees the masked tokens unless the provider echoes one that the reply-side restore cannot match (rare, and visible as a
[LABEL_xxxxxxxx]string). - The provider sees masked tokens in place of personal data, and your provider key. It never sees your zer0pii key.
- zer0pii sees the request in memory for the duration of the call and keeps metadata only: counts, mode, latency, key prefix and a hash. The console's Audit log shows exactly that and nothing else (see verify.md).