Skip to main content

raipii Python SDK

Detect and sanitize PII before it reaches your LLM. Replace real data with tokens or realistic fakes. Restore original values after the model responds.

PyPI version Python 3.8+


Install

pip install raipii

Requires Python 3.8+. The only dependency is requests.


Quick start

import raipii

ps = raipii.Raipii(api_key="ps_live_...")

# 1. Sanitize — strip PII before sending to your LLM
result = ps.sanitize(
    "Hi, I'm John Smith — john@acme.com, SSN 392-45-7810",
    mode="fake_substitute",
)
print(result.sanitized_text)
# "Hi, I'm Michael Torres — m.torres@email.net, SSN 847-23-1956"

# 2. Call your LLM with the sanitized prompt
llm_response = your_llm(result.sanitized_text)

# 3. Restore — put original values back in the response
original = ps.restore(llm_response, result.session_id)
print(original.restored_text)
# "Hi, I'm John Smith — john@acme.com, SSN 392-45-7810"

Set RAIPII_API_KEY in your environment to avoid passing the key in code:

export RAIPII_API_KEY=ps_live_...
ps = raipii.Raipii()  # reads RAIPII_API_KEY automatically

Get a free API key (2M chars/month) at raipii.com.


Sanitize modes

token (default)

Replaces PII with labelled placeholder tokens. Safe, lossless, fully reversible.

result = ps.sanitize(
    "Schedule a call with Jane Doe at jane@corp.com on 555-867-5309",
    mode="token",
)
print(result.sanitized_text)
# "Schedule a call with [PERSON_1] at [EMAIL_1] on [PHONE_1]"

# Each token maps back to its original value on restore
restored = ps.restore(llm_response, result.session_id)

fake_substitute

Replaces PII with realistic Faker-generated values. The LLM sees natural data and produces better output. All substitutions are reversed on restore.

result = ps.sanitize(
    "Write a summary for John Smith, DOB 1985-03-12, SSN 392-45-7810",
    mode="fake_substitute",
)
print(result.sanitized_text)
# "Write a summary for Michael Torres, DOB 1991-07-24, SSN 847-23-1956"

restored = ps.restore(llm_response, result.session_id)
# LLM response has fake values swapped back to real ones

redact

Replaces PII with [REDACTED]. One-way — there is nothing to restore. Use when the LLM response must never reference PII at all.

result = ps.sanitize(
    "Patient John Smith, MRN 00123456, DOB 1985-03-12",
    mode="redact",
)
print(result.sanitized_text)
# "Patient [REDACTED], MRN [REDACTED], DOB [REDACTED]"

Detect only

Scan text for PII without modifying it. Useful for logging, compliance auditing, or deciding whether to sanitize.

result = ps.detect("My SSN is 392-45-7810 and email is john@acme.com")

print(result.pii_detected)   # True
print(result.risk_level)     # "HIGH"

for entity in result.entities_found:
    print(f"  {entity.type}: {entity.value!r} at {entity.position} ({entity.confidence:.0%} confidence)")
# US_SSN: '392-45-7810' at (10, 21) (100% confidence)
# EMAIL:  'john@acme.com' at (35, 48) (100% confidence)

Risk levels: NONE → LOW → MEDIUM → HIGH

Risk Triggered by
HIGH SSN, credit card, MRN, bank account, tax ID
MEDIUM Person name, email, date of birth, address
LOW Any other detected entity
NONE No PII found

Detected entity types

Type Example Tier
PERSON John Smith All tiers
EMAIL john@acme.com All tiers
PHONE 555-867-5309 All tiers
US_SSN 392-45-7810 All tiers
CREDIT_CARD 4111 1111 1111 1111 All tiers
DATE_OF_BIRTH 1985-03-12 All tiers
ADDRESS 123 Main St, Austin TX Growth+
IP_ADDRESS 192.168.1.1 All tiers
MEDICAL_RECORD_NUMBER MRN 00123456 All tiers
BANK_ACCOUNT 12345678 All tiers
TAX_ID 12-3456789 All tiers
IBAN GB29 NWBK 6016 1331 9268 19 All tiers
JWT eyJhbGci... All tiers
AWS_KEY AKIA... All tiers

Starter tier detects structured PII reliably. Growth and Business tiers add enhanced contextual detection with higher accuracy for unstructured entities such as names and addresses.


Multi-turn conversations

Keep consistent fake substitutions across all turns of a conversation. The same entity always maps to the same fake value within a session.

conv = ps.conversations.create(ttl=86400)  # 24hr TTL

# Turn 1
turn1 = ps.sanitize(
    "My name is John Smith. What should I know about my account?",
    mode="fake_substitute",
    conversation_id=conv.conversation_id,
)
llm_reply_1 = your_llm(turn1.sanitized_text)
response1 = ps.restore(llm_reply_1, turn1.session_id)

# Turn 2 — "John Smith" maps to the SAME fake name as turn 1
turn2 = ps.sanitize(
    "What were you saying about John Smith earlier?",
    mode="fake_substitute",
    conversation_id=conv.conversation_id,
)
llm_reply_2 = your_llm(turn2.sanitized_text)
response2 = ps.restore(llm_reply_2, turn2.session_id)

Error handling

from raipii import (
    AuthenticationError,
    QuotaExceededError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    ServiceUnavailableError,
)

try:
    result = ps.sanitize(text)
except AuthenticationError:
    # Invalid or missing API key
    print("Check your API key at raipii.com")
except QuotaExceededError:
    # Monthly character limit reached
    print("Upgrade your plan at raipii.com")
except NotFoundError:
    # Session expired or not found
    print("Session expired — re-sanitize the original text")
except RateLimitError:
    # Too many requests — SDK retries automatically, this means retries exhausted
    print("Rate limit hit")
except ServiceUnavailableError:
    # Detection backend temporarily unavailable — SDK retried 3 times
    print("Service unavailable, try again shortly")
except ValidationError as e:
    print(f"Bad request: {e}")

All exceptions inherit from raipii.RaipiiError and expose .status_code and .response.


Retry behaviour

The SDK automatically retries on 429 Too Many Requests and 503 Service Unavailable with exponential backoff:

Attempt Delay
1st retry 1s
2nd retry 2s
3rd retry 4s

Default max_retries=3. Override:

ps = raipii.Raipii(api_key="...", max_retries=5)
ps_no_retry = raipii.Raipii(api_key="...", max_retries=0)

Client options

ps = raipii.Raipii(
    api_key="ps_live_...",    # or RAIPII_API_KEY env var
    base_url="https://api.raipii.com",  # override for testing
    timeout=30,               # request timeout in seconds
    max_retries=3,            # retries on 429/503
)

Return types

SanitizeResult

Field Type Description
session_id str Pass to restore()
sanitized_text str Text with PII replaced
entities_found list[EntityFound] Each detected entity
char_count int Characters processed
usage.chars_billed int Characters billed
conversation_id str | None Echo of the conversation_id passed in

RestoreResult

Field Type Description
restored_text str Text with original PII restored
substitutions_reversed int Number of tokens replaced
usage.chars_billed int Characters billed

DetectResult

Field Type Description
entities_found list[DetectedEntity] Detected PII entities
pii_detected bool True if any PII found
risk_level str NONE / LOW / MEDIUM / HIGH
usage.chars_billed int Characters billed

Caveats

  • Session TTL — sessions expire after session_ttl seconds (default 1hr). Calling restore() after expiry raises NotFoundError. Store the session_id and call restore promptly after getting the LLM response.
  • redact mode has no restore — [REDACTED] tokens contain no reversible information. Calling restore() on a redact session returns the text unchanged.
  • Conversation TTL — conversation sessions expire after their TTL (default 24hr). After expiry, new turns start a fresh mapping.
  • Characters billed — both sanitize and restore bill by character count of the input text. detect also bills. Free tier: 2M chars/month.
  • Starter tier detects structured PII reliably. Upgrade to Growth for enhanced contextual detection of names and addresses in free-form text.

Get an API key

Free tier — 2M characters/month, no credit card required: raipii.com

Metadata

Release files for raipii 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for raipii 0.1.0
File Size Uploaded
raipii-0.1.0.tar.gz 9.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for raipii 0.1.0
File Interpreter ABI Platform
raipii-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 18.6 kB

Release files / raipii-0.1.0.tar.gz

Download URL raipii-0.1.0.tar.gz
Size 9.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b346d07643b70b9934a75996a26cffccb00d4e90aaac4394ec4d97d9d987965c
BLAKE2b-256 checksum
How to use checksums
4835f059be93f80dce51efe359e2998777131f305252e9d46732a85de5da3bd7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / raipii-0.1.0-py3-none-any.whl

Download URL raipii-0.1.0-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
62f15bbe25a0d623954dabcd0c19484112c9400cf4ad3796662c48eb8bb8c568
BLAKE2b-256 checksum
How to use checksums
0d1687bd8e196f272490979f045b2b7ae9d934e4ee5312dcc51b57b94350db0a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page