Client API Reference
The endpoints the SDKs call, for tokenizing text before it reaches your backend and revealing it on the way back. LLM traffic still goes through the proxy.
Authentication
Every call takes Authorization: Bearer <credential>, where the credential is a secret key, a publishable key, or a client session token. See Keys and reveal policy for what each may do. Optionally send X-NoPII-Session-Id to continue a session.
Client sessions
POST /v1/client-sessions
Secret key with client_session:create.
// Request
{ "end_user_id": "user-42", "ttl_seconds": 900 }
// Response
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2026-09-16T01:34:07+00:00",
"end_user_id": "user-42",
"scopes": ["tokenize", "detokenize:own", "proxy:forward"]
}Default lifetime 15 minutes, maximum 1 hour. Mint a new one to refresh.
GET /v1/client/session-info
The caller's tenant, kind, scopes, end user, and expiry.
Tokenize and detect
POST /v1/client/tokenize
Any credential with tokenize.
// Request
{ "texts": ["Call John Smith at john@example.com"], "session_id": "b7c1f0e2-...", "end_user_id": "user-42" }
// Response
{
"texts": ["Call [NAME: aBcDeFgH] at [EMAIL: kLmNoPqR]"],
"entities": [
{ "entity_type": "PERSON", "label": "NAME", "token": "aBcDeFgH", "score": 0.85,
"masked_value": "J*********", "start": 5, "end": 15, "text_index": 0 }
],
"tokens": { "aBcDeFgH": "John Smith", "kLmNoPqR": "john@example.com" },
"session_id": "b7c1f0e2-...",
"entity_count": 2
}tokens maps back only values submitted in this call, so the caller can reveal them locally without another request. With a client session, the session's end user always wins over end_user_id in the body. Limits: 100 texts and 200,000 characters per call. Submitted text counts toward protected tokens.
POST /v1/client/detect
Same request. Entities come back with token: null. Nothing is tokenized, and it is not metered.
Reveal
POST /v1/client/detokenize
// Request
{ "tokens": ["aBcDeFgH"], "text": "Hello [NAME: aBcDeFgH]", "session_id": "b7c1f0e2-...", "grant_id": null }
// Response
{
"tokens": { "aBcDeFgH": { "status": "revealed", "plaintext": "John Smith" } },
"text": "Hello John Smith"
}Status per token is revealed, forbidden, purged, or not_found, decided by the reveal policy. A partial result returns 200. Pass grant_id to use a reveal grant; an invalid one is refused with 403. Limit: 500 tokens per call.
GET /v1/client/pretext?labels=NAME,EMAIL
The system prompt that explains tokens to a model, for when you call an LLM directly with tokenized text. The proxy adds it for you.
Reveal grants
POST /v1/reveal-grants
Secret key with reveal_grant:create.
{
"subject_end_user_id": "customer-42",
"grantee_end_user_id": "support-agent-7",
"ttl_seconds": 900,
"reason": "ticket 4412"
}Needs subject_end_user_id, tokens, or both. Returns the grant with its id, created_at, and expires_at.
DELETE /v1/reveal-grants/{grant_id}
Revokes the grant immediately. Idempotent.
Tokens-only proxy mode
Add X-NoPII-Mode: tokens-only to a proxy request whose messages are already tokenized. NoPII explains the tokens to the model, tokenizes anything that was missed, and returns the reply with tokens in place, streamed tool call arguments included. Pass the browser's X-NoPII-Session-Id so the user can reveal the reply.
Errors
| Status | Cause |
|---|---|
| 401 | Missing, unknown, revoked, or expired credential. An expired session also sends X-NoPII-Error-Code: session_expired. |
| 403 | Missing scope, or a publishable key used from an unlisted origin or with no Origin header |
| 413 | Too many texts, characters, or tokens |
| 429 | Rate limit exceeded |
| 503 | Tokenization is unavailable. Nothing is returned, so partially protected text never reaches you. |
Browsers can read X-NoPII-Session-Id, X-NoPII-Entity-Count, X-NoPII-Labels, and X-NoPII-Error-Code from responses.
Related
- SDKs: use these endpoints without writing HTTP calls
- Proxy API reference: chat completions, responses, and messages