For IT teams
The same protection, called by your programs — one stateless image to run.
Before a workflow sends a document to an AI, a translator or a supplier, it can ask DoNotLeak to find and replace the personal data in it — through an identified API, answered by the engine behind the page.
One more component to host, secure, update and monitor? Here is what it asks: a signed image, with no database and no volume to back up, configured by its environment, called by identified machines. And, on request, its source code for your teams.
Identified callers only · Nothing kept · Signed images, amd64 and arm64

Try the API
Send a request, read the answer.
The real engine, open here as a demo, with no key: the answer you read is the one your programs will receive.
- 1 call every 15 s per IP address
- texts up to 4 KB
- nothing is kept
- one network shares the pace
The demo's ceilings
Per address — an IPv6 /64 network counts as one: 100 calls a day, 300 a week, 600 a month, 2,000 a year. For the whole demo: 600 calls a minute and one text scanned at a time; beyond that it answers 503 and the rest of the service is untouched. Your address is held in memory only, while its calls are counted; the logs keep the verb, the status, the sizes and the duration — never the address, the text or the answer.
RateLimit-Policy · RateLimit · Retry-After
- POSTscan
- POSTprotectSoon
- POSTrestoreSoon
- GETcapabilitiesSoon
- POSTextractwith a key
- POSTrenderwith a key
Request
POST/api/demo/scan
Finds the personal data — where it is (in UTF-8 bytes), its type, its severity — and returns the protected text.
81 / 4096 bytes
See the JSON sent
{
"text": "Damien Morel a validé le virement vers l'IBAN FR76 3000 6000 0112 3456 7890 189.",
"scope": [
"FR"
]
}Ready — 1 call available
Response
The answer will show here.
Your programs call /api/v1/scan with their identity — a client certificate or a token: that is the next section.
The API
What it does today: find, then replace.
One call: JSON in, the findings and the protected text out. The page’s own engine answers it.
Find
Every personal value in the text, with its type, its position and a confidence score. The formats follow the countries you name.
findings · counts · scope
Replace
The same answer carries the protected text: each value becomes a typed, numbered placeholder. The values you list as kept stay as they are.
anonymized_text · replacements · kept
The call
curl -sS --cacert ca.pem --cert client.pem --key client.key \
-H 'Content-Type: application/json' \
-X POST --data '{"text":"Contact: jean.dupont@example.org"}' \
https://donotleak.example.org/api/v1/scanWith a token instead of a certificate
-H "Authorization: Bearer $TOKEN"The answer — recorded from the engine, line breaks added
{"version":1,
"findings":[{"id":0,"kind":"Pii","span":{"start":9,"end":32},
"primary":{"label":"EMAIL","severity":"Medium","confidence":85},
"alternatives":[],"entity_id":0,"kept":false,"applied":0}],
"counts":{"total":1,"low":0,"medium":1,"high":0,"critical":0},
"anonymized_text":"Contact: [[EMAIL-1]]",
"replacements":[{"span":{"start":9,"end":32},"placeholder":"[[EMAIL-1]]"}],
"entities":[{"id":0,"label":"EMAIL","value":"jean.dupont@example.org",
"placeholder":"[[EMAIL-1]]"}],
"skipped_overlaps":0}Refusals and the entity table
Refusals never quote the content: 400 empty or not JSON, 413 over 1 MiB, 422 suspicious content, 401 no identity, 403 not permitted, 429 over budget.
The entity table returns each original value to the caller that sent it — it is what makes restoring possible. Only the protected text goes on to the AI.
What it does not do yet
- Restore: put the originals back into the AI’s answer Soon
- Word documents through the API Soon
- The published v1 contract: an OpenAPI description, uniform errors, quotas per caller Soon
Where it fits in your workflows
A check before the external call.
A workflow — a document management system, a CRM, a batch of files — calls DoNotLeak just before it calls an AI or a partner. Only the protected text goes on.
You choose where the check sits and what follows: send at once, or let a person review the findings first and send the text again with the values the task needs kept.

Machine identity
Never anonymous: every call names its caller.
The API has no open door. The server refuses to start until it knows how to identify a caller, and each call is judged against your policy.
A client certificate
Mutual TLS, terminated by the server itself: the certificate must chain to the authority you trust, and its SPIFFE ID — else its DNS name, never its common name — becomes the caller.
TLS_CLIENT_CA · TLS_CLIENT_IDENTITY=san
A token from your identity provider
The OpenID Connect issuer you name — your directory, your SSO: each token’s signature, issuer, audience and expiry are checked against the keys it publishes, and its roles come with it.
OIDC_ISSUER_URL · OIDC_CLIENT_ID · proven in CI against Keycloak
- Deny by default: a caller with no role in your policy file is refused (403), and scanning is a right of its own.
- No static API key to leak: a caller proves itself with a certificate or a signed token.
Hosting and sovereignty
Hosted by Contee, or inside your own information system.
The same headless image in both.
By Contee, in the EU
Contee operates the server, you call it. The public page already runs this way, with OVH SAS, a French host (see the legal notice).
The hosted API, under its own service contract Soon
Inside your information system
The image runs on your servers, behind your PKI and your identity provider: the texts never leave your estate. On request, with its source code: the on-premises offer, below.

The on-premises offer
The source code in your hands, and your teams to take it further.
For an organisation that wants DoNotLeak inside its own information system, without depending on Contee to keep it alive.
The source code delivered
For your organisation’s internal use: your teams read it, build it and deploy it inside your estate.
Your teams trained
To maintain it, improve it and extend it: the skills are built in-house, not at ours.
The least lock-in possible
The code and the know-how stay in-house; the server reaches only what you configure, never a Contee service.
One-shot, not a SaaS subscription
Available today, on request, for your estate.
The headless image
The scan core alone — signed, for two architectures.
No page, no cookie, no browser code: the API and the engine, nothing else.
The page’s engine
The page and the API call the same scan function: what a person sees on the page is what a program gets.
one core · two doors
Small, and closed by default
A distroless base — no shell, no package manager — and a non-root user. It refuses to start without an identity source, or with half a TLS configuration.
port 3000 · TLS and mTLS in the app, or behind your proxy
Built and signed like the web image
The same pipeline builds and scans it, then signs it by digest with DoNotLeak’s own key — the image, its bill of materials and its build provenance.
amd64 + arm64 · cosign · SPDX SBOM · SLSA provenance · Trivy, Grype, Dockle, Dive
Operations
What the image asks of your operations.
One container among the others.
Stateless
No database, no volume to back up: each request is processed in memory, then forgotten. Nothing to restore.
no database · no data volume
Configured by its environment
Listening address, certificates, client authority, OIDC issuer, policy file, budgets: variables, and files mounted read-only. Half a configuration refuses to start.
LEPTOS_SITE_ADDR · TLS_CERT · TLS_CLIENT_CA · CASBIN_POLICY_FILE · SCAN_*
Monitored by your tools
Traces go out over OpenTelemetry to your collector, or else to standard output; the logs never hold a scanned text.
OTEL_EXPORTER_OTLP_ENDPOINT
Updated by digest
A release is a signed image named by its digest: check the signature, change the digest, restart. A certificate that changes: new files, then a restart.
cosign verify · amd64 + arm64
Wherever it runs
Three things that do not change.
Nothing kept
Each text is analysed in the memory of the request that carries it, on the server, and dropped with it: no copy, no log of its content.
Every pipeline sends a canary through the headless server and fails if its log ever shows it.
No one else called
The detection runs on formats, rules and dictionaries: no language model, no third-party service. The server reaches only what you configure — your identity provider, your telemetry collector.
Every release verifiable
Each image is signed by digest, with its bill of materials and its provenance; the pipeline checks the signature before anything ships.

Try it on the page, then message Contee.
The page answers with the same engine as the API: paste a typical text from your workflows. The image’s security is checked control by control on the CISO page. For the hosted API or the on-premises offer, message Contee.