Python SDK

nopii-sdk is the server half of a protected app for Python: client sessions for your frontend, proxy settings for the official OpenAI and Anthropic clients, and server-side tokenization. Sync and async.

Preview

The SDKs are in preview and not yet published to npm or PyPI. Package names and APIs may change before 1.0.

Install

bash
pip install nopii-sdk
python
import os
from nopii_sdk import NoPII

nopii = NoPII(secret_key=os.environ["NOPII_SECRET_KEY"])

Install nopii-sdk, import nopii_sdk

The package named nopii on PyPI is an unrelated project. pip install nopii installs someone else's code.

Python 3.10 or later. One instance is safe to share across threads and requests.

Mint client sessions

Your frontend asks your server for a session. Bind it to your own user id, so that user, and only that user, can reveal their earlier messages.

python
# FastAPI
@app.post("/api/nopii-session")
def nopii_session(user: User = Depends(current_user)):
    session = nopii.client_sessions.create(end_user_id=user.id, ttl_seconds=900)
    return {"token": session.token, "expiresAt": session.expires_at.isoformat()}

Forward messages to the LLM

The browser sends your route tokens. Forward them in tokens-only mode, passing the request headers so the browser's NoPII session carries through.

python
from openai import OpenAI
from anthropic import Anthropic

@app.post("/api/chat")
async def chat(request: Request):
    body = await request.json()  # already tokenized in the browser
    client = OpenAI(
        api_key=os.environ["OPENAI_API_KEY"],
        **nopii.openai_options(request_headers=request.headers, mode="tokens-only"),
    )
    return client.chat.completions.create(model="gpt-4o", messages=body["messages"])

    # For Anthropic, inside the same kind of handler:
    # claude = Anthropic(
    #     api_key=os.environ["ANTHROPIC_API_KEY"],
    #     **nopii.anthropic_options(request_headers=request.headers, mode="tokens-only"),
    # )

The reply comes back tokenized, and the browser SDK reveals it for the user. Use openai_options for OpenAI and anthropic_options for Anthropic: the Anthropic client adds /v1/messages itself, so one shared base URL cannot serve both.

Sessions deeper in your code

python
client = OpenAI(api_key=..., **nopii.openai_options())

with nopii.session(session_id, mode="tokens-only"):
    summarize(client, thread)  # every proxy call in here carries the session

The session lives in a context variable, so each thread and each asyncio task keeps its own.

Tokenize on the server

python
result = nopii.tokenize(["Contract signed by Wei Chen"], end_user_id=customer.id)
result.texts[0]  # "Contract signed by [NAME: ...]"

found = nopii.detect(["Is there PII in here?"])  # not tokenized, not metered

revealed = nopii.detokenize(["8f2kQ1xZ"], session_id=session_id)
revealed.tokens["8f2kQ1xZ"].status  # "revealed", "forbidden", "purged", or "not_found"

Reveal grants

Let a support agent read a customer's conversation for a limited time. Every reveal under the grant is logged.

python
grant = nopii.reveal_grants.create(
    subject_end_user_id=ticket.customer_id,
    grantee_end_user_id=agent.id,
    ttl_seconds=900,
    reason=f"ticket {ticket.id}",
)
# The agent's browser passes grant.id when revealing.
nopii.reveal_grants.revoke(grant.id)

Async

python
from openai import AsyncOpenAI
from nopii_sdk import AsyncNoPII

nopii = AsyncNoPII(secret_key=os.environ["NOPII_SECRET_KEY"])

session = await nopii.client_sessions.create(end_user_id=user.id)
client = AsyncOpenAI(api_key=..., **nopii.openai_options(request_headers=request.headers, mode="tokens-only"))

Errors

ExceptionWhen
NoPIIUnavailableErrorNoPII could not be reached or had a server error. Nothing was tokenized.
NoPIIAuthErrorThe key was rejected, or lacks the scope for the call.
NoPIIRequestErrorThe request was invalid, for example too many texts.

All three derive from NoPIIError.

HTTP libraries

Current openai and anthropic releases are built on httpx2, and anthropic rejects an httpx client. The SDK builds its proxy client on httpx2 when it is installed. For older client versions, pass http_library="httpx" to NoPII.

Related