Built by developers, for developers.
Plain REST, a stdlib-only Python SDK, and an inline gateway for legacy APIs. Bearer auth with claim-to-scope mapping, idempotency keys on writes, and a job API for async work.
Your data stays yours. We never see it.
The most common question we get from engineering teams is the right one: "If I send a value to your API, doesn't that mean you hold the PII?" No. Tokenization is not a proxy. Sensitive values post directly to the vault under your keys, in your region. What your application stores, logs, and ships is the token — an opaque reference that cannot be reversed outside the vault. The original value never traverses your servers, your logs, or our infrastructure in a readable form.
This is the same protection model that Apple, Visa, Google and other global platforms use to keep card and identity data out of their own application tiers — Zero Trust Architecture applied to data, not just to networks. What used to require a billion-dollar engineering org is now an API call.
Seven endpoints. Zero raw data.
| Method + path | Does | Auth scope | Time |
|---|---|---|---|
| POST /v1/tokens | Tokenize a value against a schema field. Returns the opaque token, token ID, a safe display value, and the policy version. | tokenize | 850 µs (0.85 ms) |
| POST /v1/tokens:batch | Tokenize many values in one call. Same per-field policy, bounded and audited per operation. | tokenize | ~13.4k /s |
| POST /v1/tokens:detokenize | Reveal tokens for a declared purpose and case reference. Purpose alone is never enough — scopes and policy decide. | field:reveal + purpose | 280 µs (0.28 ms) |
| POST /v1/tokens:reveal-masked | Return a masked display form (last-four, redacted) without ever exposing the raw value. | mask | — |
| POST /v1/transform:mask | One-way masking (keep_suffix, redact_all) for logs and support views. | mask | — |
| POST /v1/transform:protect | Per-call choice of protection method from the field’s menu — tokenize, mask, or redact. | tokenize / mask | — |
| POST /v1/search | Approved exact-match lookup over the blind index. Unapproved fields return 403, never data. | search:approved | 340 µs (0.34 ms) |
| POST /v1/records:delete | Crypto-erase a record; returns a job to poll. Values are never written to the audit trail. | delete | async |
| GET /v1/jobs/{jobId} | Poll async work — deletes, retention, re-encryption. Stable IDs for reconciliation. | job scope | — |
Time column shows application-level P50 where a committed benchmark exists; "—" means not separately measured. Every call is policy-evaluated server-side, and the purpose string is required on detokenization — the SDK rejects the call locally without it.
# POST /v1/tokens — Idempotency-Key required on writes
{
"schema": { "id": "customer-contact", "version": 3 },
"field": "email", "value": "person@example.test",
"context": { "purpose": "customer-account" }
}
# → 200 — the token is opaque and random by default
{
"token": "cl_tkn_v1_4V8…", "tokenId": "tok_01J…",
"status": "active", "policyVersion": "policy-42"
}
from cloak import Client
c = Client("https://vault.your-domain", "<workload-token>")
tok = c.tokenize("mobile_number", "+919876543210",
idempotency_key="order-123")
print(tok["token_id"], tok["display"]) # display is the safe masked value
print(c.detokenize(tok["token_id"])) # scope + purpose checked
Short-lived everything
Bearer workload tokens, OIDC / AWS / GCP / Azure / Okta verifiers, claim-to-scope mapping. Denylist and kill switch included.
Fail-closed defaults
Unknown fields rejected on protected routes, ciphertext never returned, batch sizes bounded and audited per operation.
Three ways in
Server SDKs for explicit integration, browser-side capture before submission, and the OpenResty gateway for legacy APIs.
Questions on integration? Book an engineer-led walkthrough — we pair on your first tokenize call.
Reveal is a decision, not a lookup.
A detokenization request: scopes and purpose are evaluated first, the vault resolves only on allow, and both outcomes are audited.
The server never trusts a purpose string alone — identity, environment, and approval evidence are evaluated too.
Failures you can code against.
| Status | Meaning | Do this |
|---|---|---|
| 401 | Missing, expired, or unverifiable credential. | Refresh the workload token and retry. |
| 404 | Unknown field path or token ID. | Check the schema version and the reference you stored. |
| 422 | Value fails the field’s validation. | Fix the input; nothing was stored. |
| 403 | Policy deny — or search_not_allowed on unapproved fields. | Request the scope or purpose; the denial is already audited. |
| 429 | Rate limited, per operation — never just per batch. | Back off with jitter; bulk endpoints stay bounded by design. |
Speak to Us to Understand More.
We will pair with your team on the first tokenize call — live, on your stack.
