Sanitext

Redact PII from documents and text files

To redact PII from documents, first extract plain text from the PDF or DOCX, then send that text to Sanitext's POST /v1/redact endpoint. It returns the text with names, emails, phones, addresses, and IDs masked as [LABEL]. Large jobs use the async bulk endpoint on Scale and Enterprise plans.

Documents hold the messiest PII: names, emails, addresses, and account numbers buried in PDFs and DOCX files. This guide shows the extract-redact-reassemble pattern, how to handle large-document latency and the async bulk endpoint, and why byte-based offsets matter when you redact text files at scale.

Single document vs bulk document redaction with Sanitext

FactorSingle documentBulk / large documents
EndpointPOST /v1/redact (synchronous)Async bulk endpoint
Best forOne file, one page, ad-hoc redactionThousands of files or 50+ page documents
PlanFree, Hobby, Pro and upScale ($499/mo) and Enterprise
Latency handlingSplit big files per page to stay fastSubmit job, poll or webhook for results
OutputMasked text in the response bodyMasked results retrieved when the job finishes
Raw text retentionNone (counts and timings only)None (counts and timings only)

Why is redacting PII from documents hard?

Documents are not plain text. A signed contract, an invoice, or a scanned report carries names, emails, phone numbers, addresses, dates, and account numbers spread across pages, tables, and footers.

Two problems stack up. First, you have to pull clean text out of the file format. PDFs and DOCX wrap text in layout markup, so you need an extractor before you can detect anything. Second, you have to find every personal data span without writing brittle regex for 30+ languages.

Regex catches an email but misses a misspelled name or a foreign address format. Manual review does not scale past a handful of files. You need detection that understands context, runs fast, and never ships your raw documents to a third-party LLM.

What is the pattern for redacting documents at scale?

The reliable pattern is three steps: extract, redact, reassemble.

Extract turns the PDF or DOCX into plain UTF-8 text using a library like pdfplumber, PyMuPDF, or python-docx. Redact sends that text to Sanitext, which returns the same text with each PII span replaced by its label, for example [FIRSTNAME] or [EMAIL]. Reassemble writes the masked text back into a new file or stores it for review.

For one file, call POST /v1/redact and write the response. For thousands of files, batch them. On Scale and Enterprise plans an async bulk endpoint accepts large payloads and returns results without holding your request open, which avoids timeouts on big documents.

Note on latency: a 50-page document is a lot of characters, and longer text takes longer to process. Split very large documents per page or per section so each call stays fast, then merge the masked output.

  • Extract: PDF/DOCX to plain text (pdfplumber, PyMuPDF, python-docx, Apache Tika)
  • Detect or redact: POST /v1/detect for spans, POST /v1/redact for masked text
  • Reassemble: write masked text into a new file or queue it for human review
  • Scale: use the async bulk endpoint for large batches and big documents

Why does Sanitext fit document redaction?

Sanitext detects 9 entity types across 30+ languages: FIRSTNAME, LASTNAME, EMAIL, PHONE, ADDRESS, DATE, URL, ACCOUNT, and SECRET, plus prefixes like Dr. That covers the personal data that shows up in real contracts, forms, and reports.

We own the open-weights model (Apache-2.0, from the OpenAI privacy-filter family) and run it on our own Cloudflare infrastructure. There is no per-token AI cost, so pricing is flat and transparent instead of metered. Your documents are never sent to a third-party LLM.

We do not retain raw text. We log counts and timings only, so the contents of your documents do not sit on our servers. Enterprise plans add EU data residency and a DPA.

Pricing is flat: Free gives a one-time 300K characters with no card. Hobby is $29/month for 12M chars, Pro $149 for 120M, Scale $499 for 450M. Overage runs $0.35 to $0.60 per 1M chars, up to about 2x cheaper than metered hyperscalers at $1.00 per 1M.

Integration notes: offsets, encoding, and review

POST /v1/detect returns spans with a label, start and end byte offsets, a score, and the matched text. POST /v1/redact returns the text with those spans masked.

Offsets are byte-based, not character-based. This matters once your text leaves ASCII. An accented name like José or a non-Latin script uses multi-byte UTF-8 characters, so slicing the original string by byte offset in a language that indexes by code point (like Python or JavaScript) will misalign. Either work on the byte representation, or use the redact endpoint, which masks the spans for you and sidesteps offset math entirely.

For documents, redact is usually the simpler call. Use detect when you need to log what was found, score-gate borderline matches, or build a custom mask format.

Redaction is a data-minimization aid, not an anonymization or compliance guarantee. A masked document can still be re-identifiable from context, and no detector catches 100% of PII. Keep a human review step for anything sensitive, and treat Sanitext as one control inside your GDPR or HIPAA process, not the whole thing.

python

import os, requests, pdfplumber

API_KEY = os.environ["SANITEXT_API_KEY"]

def extract_text(pdf_path):
    # Pull plain text out of the PDF, page by page
    with pdfplumber.open(pdf_path) as pdf:
        return "\n".join(page.extract_text() or "" for page in pdf.pages)

def redact(text):
    # Send plain text to Sanitext; get masked text back as [LABEL]
    resp = requests.post(
        "https://api.sanitext.app/v1/redact",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"text": text},
        timeout=60,
    )
    resp.raise_for_status()
    return resp.json()["text"]

# Long docs take longer, so redact per page to keep each call fast
with pdfplumber.open("contract.pdf") as pdf:
    pages = [page.extract_text() or "" for page in pdf.pages]

masked = "\n".join(redact(p) for p in pages if p.strip())

with open("contract.redacted.txt", "w", encoding="utf-8") as f:
    f.write(masked)

print(masked[:500])
# John Smith -> [FIRSTNAME] [LASTNAME], j.smith@acme.com -> [EMAIL]

FAQ

Can Sanitext read PDF or DOCX files directly?+

No. Sanitext works on plain text, not file formats. You extract text from the PDF or DOCX first with a library like pdfplumber, PyMuPDF, or python-docx, then send that text to POST /v1/redact. This keeps the API simple and lets you choose any extractor.

How do I handle large documents without timeouts?+

Longer text takes longer to process. Split large documents per page or per section so each /v1/redact call stays fast, then merge the masked output. For thousands of files or very large documents, use the async bulk endpoint available on Scale and Enterprise plans.

Why are the offsets byte-based and does it matter?+

POST /v1/detect returns start and end byte offsets, not character offsets. With accented names or non-Latin scripts, slicing by byte in Python or JavaScript can misalign. Use the /v1/redact endpoint, which masks spans for you, or operate on the byte representation directly.

Are my documents stored or sent to a third-party LLM?+

No. Sanitext runs our own open-weights model on our own Cloudflare infrastructure, so text never goes to an external LLM. We do not retain raw text; we log counts and timings only. Enterprise adds EU data residency and a DPA.

Does redacting a document make it compliant or anonymous?+

No. Redaction is a data-minimization aid, not an anonymization or compliance guarantee. Masked documents can still be re-identifiable from context, and no detector finds 100% of PII. Use Sanitext as one control inside your GDPR or HIPAA process, with human review for sensitive files.

Redact your first document in 60 seconds

Sign up free for a one-time 300K characters, no card needed. Get an API key, extract text from your PDF, and pipe it through /v1/redact. Flat pricing, EU residency on Enterprise, and your raw text is never stored.

Get your free API key