Python SDK for the Ciphyrs PII Shield API
Project description
Ciphyrs — PII Shield for AI Workflows
Intercept, mask, and restore PII before it reaches any LLM. Works with LangChain, CrewAI, or any Python application.
Install
pip install ciphyrs # core SDK
pip install 'ciphyrs[langchain]' # + LangChain integration
pip install 'ciphyrs[crewai]' # + CrewAI integration
pip install 'ciphyrs[all]' # everything
Quick Start
from ciphyrs import CiphyrsClient
client = CiphyrsClient(
api_key="cyp_live_...",
base_url="https://www.ciphyrs.com"
)
# Mask PII
result = client.mask("Contact Praveen at 9876125640 and praveen@acme.com")
print(result.masked_text)
# "Contact XXXX_a1b2c3 at XXXX_d4e5f6 and XXXX_g7h8i9"
# Restore PII
restored = client.restore(result.masked_text, result.session_id)
print(restored.restored_text)
# "Contact Praveen at 9876125640 and praveen@acme.com"
One-Shot Protect (recommended)
protect() wraps mask → LLM call → restore so you can't accidentally
ship [PERSON_1] to end users:
from openai import OpenAI
oai = OpenAI()
result = client.protect(
user_message,
lambda masked, ctx: oai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": masked}],
).choices[0].message.content,
)
return result["output"] # "Hello John, ..." — never "[PERSON_1]"
Active Blocking — Guard (V58)
Inline <50ms allow/block decision, 5 detection layers:
# Option 1 — manual check
guard = client.guard_check(input=user_msg, agent_name="support-bot")
if guard["decision"] == "block":
return {"error": guard["reason"]}, 400
# Option 2 — full wrap
result = client.guard_wrap(user_msg, lambda inp:
oai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": inp}],
).choices[0].message.content
)
if result["blocked"]:
return {"error": result["reason"]}, 400
return {"reply": result["output"]}
Security Operations (V55-V59)
# List recent attacks
detections = client.list_detections(days=7, severity="high")
# Plant a honeypot canary
created = client.create_canary(name="fake-admin-secret", scope="output")
print(created["token"]) # save this; plant it where it shouldn't appear
# Generate compliance evidence PDF
report = client.generate_prod_report(
title="Q4 SOC 2 Evidence",
range_start="2026-10-01",
range_end="2026-12-31",
sections=["security_incidents", "pii_detections", "performance", "cost"],
)
pdf_bytes = client.download_prod_report_pdf(report["report"]["id"])
open("soc2-evidence.pdf", "wb").write(pdf_bytes)
# Share with auditors (no login required)
share = client.share_prod_report(report["report"]["id"], ttl_days=30)
print(share["share_url_path"])
Authentication
All API calls require an x-api-key header. Get your API key from the Ciphyrs Dashboard.
- Register at ciphyrs.com/register
- Go to Settings > API Keys
- Click Generate API Key
- Copy the key (starts with
cyp_live_)
LangChain Integration
Option 1: Callback Handler (auto-masks all LLM calls)
from langchain_openai import ChatOpenAI
from ciphyrs.integrations.langchain import CiphyrsPIICallback
callback = CiphyrsPIICallback(api_key="cyp_live_...")
llm = ChatOpenAI(model="gpt-4o", callbacks=[callback])
# PII is automatically masked before reaching OpenAI
# and restored in the response
result = llm.invoke("Hi, I'm Praveen Kumar, my phone is 9876125640")
Option 2: LCEL Runnables (pipe operator)
from ciphyrs.integrations.langchain import CiphyrsMaskRunnable, CiphyrsRestoreRunnable
session = {}
mask = CiphyrsMaskRunnable(api_key="cyp_live_...", session_store=session)
restore = CiphyrsRestoreRunnable(api_key="cyp_live_...", session_store=session)
# Build pipeline: mask -> prompt -> llm -> restore
chain = mask | prompt_template | llm | restore
result = chain.invoke({"input": "Call Praveen at 9876125640"})
Option 3: Shield Wrapper (wrap any chain)
from ciphyrs.integrations.langchain import CiphyrsShield
shield = CiphyrsShield(api_key="cyp_live_...")
safe_chain = shield.wrap(my_existing_chain)
result = safe_chain.invoke({"input": "Praveen's email is praveen@acme.com"})
Async Support
from ciphyrs import AsyncCiphyrsClient
async with AsyncCiphyrsClient(api_key="cyp_live_...") as client:
result = await client.mask("Contact Praveen at praveen@acme.com")
restored = await client.restore(result.masked_text, result.session_id)
Detected Entity Types
| Entity | Example |
|---|---|
| PERSON | Praveen Kumar |
| praveen@acme.com | |
| PHONE | 9876125640 |
| IN_AADHAAR | 2345 6789 0123 |
| IN_PAN | ABCDE1234F |
| CREDIT_CARD | 4111-1111-1111-1111 |
| IP_ADDRESS | 192.168.1.1 |
| DATE_OF_BIRTH | 15/03/1990 |
| LOCATION | Mumbai |
| ORGANIZATION | Acme Corp |
| API_KEY | sk-abc123... |
Links
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ciphyrs-2.5.0.tar.gz.
File metadata
- Download URL: ciphyrs-2.5.0.tar.gz
- Upload date:
- Size: 56.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2001a1f4090fdac80a6e7f4ffc2a7b77332ac88ddd55838845df9d1bcf31c4d6
|
|
| MD5 |
3e4280215ed12ed6a1787248096a6968
|
|
| BLAKE2b-256 |
5677accbc7cf3b4e50fd67f96bceaea0c95232fc07446c815a40d4fb0b0d43f2
|
File details
Details for the file ciphyrs-2.5.0-py3-none-any.whl.
File metadata
- Download URL: ciphyrs-2.5.0-py3-none-any.whl
- Upload date:
- Size: 84.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c37b0f63bb713149734b6bd9e35ef8c1e66766822681f9b0807b93bc5f98901
|
|
| MD5 |
1d992fad5bcca8c5c96d5f6dd09eff55
|
|
| BLAKE2b-256 |
51b514442d35eaf539fd3b94646cd2bf4949124eb8bc23f9e80e971c97f5ac0e
|