> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Portable Encryption overview

> Encrypt any JSON, get back a self-describing kc: ciphertext you can store anywhere. Public-key encryption so plaintext can be sealed before it ever reaches KnoxCall, plus single-use client-side reveal tokens.

# Portable Encryption overview

KnoxCall's **Portable Encryption** turns any value into a single, self-describing **`kc:` ciphertext string** you can drop into a database column, a log line, or a message queue with no schema change — and which carries everything needed to decrypt it *except* the private key.

It is public-key encryption: you encrypt against a tenant **public key**, and only KnoxCall (holding the matching private key, wrapped under your [tenant master key](/essentials/key-management/tenant-master-key)) can decrypt. That means plaintext can be sealed **before it ever reaches KnoxCall** — including in a browser.

Use it for:

* **"Encrypt anything, store it anywhere"** — PII, PHI, PAN, API responses, free-form blobs. The ciphertext is portable across systems.
* **Structure-preserving encryption** — send a whole JSON object; get the same shape back with every scalar leaf replaced by a `kc:` string.
* **Frontend scope reduction** — seal card/PII data in the page so it never touches your servers (paired with the browser SDK).
* **Crypto-agility** — every `kc:` value carries its scheme version, so the format can evolve without breaking stored data.

## Quick example

```bash theme={"dark"}
# Encrypt — structure-preserving. Scalar leaves become kc: strings.
curl -X POST https://api.knoxcall.com/v1/encrypt \
  -H "Authorization: Bearer $KC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "data": { "card": "4242424242424242", "amount": 1299 } }'
# → { "data": { "card": "kc:1:s:...:$", "amount": "kc:1:n:...:$" }, "key": "kc-default", "key_version": 1 }

# Decrypt — non-kc values pass through untouched.
curl -X POST https://api.knoxcall.com/v1/decrypt \
  -H "Authorization: Bearer $KC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "data": { "card": "kc:1:s:...:$", "amount": "kc:1:n:...:$" } }'
# → { "data": { "card": "4242424242424242", "amount": 1299 } }

# Inspect — metadata about a ciphertext WITHOUT decrypting it.
curl -X POST https://api.knoxcall.com/v1/inspect \
  -H "Authorization: Bearer $KC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "value": "kc:1:s:...:$" }'
# → { "encrypted": true, "scheme": "kc", "version": 1, "datatype": "s", "key_ref": {...}, "fingerprint": "..." }
```

If you don't name a `key`, KnoxCall auto-provisions a default `ecdh-p256` key on first use — the happy path is zero-config. To pin a key, pass `"key": "my-key"` (create it with `key_type: "ecdh-p256"` via [Crypto Keys](/essentials/crypto-keys/crypto-keys-overview)).

## Data roles

Pass an optional `role` on encrypt to bind a **data-role** into the ciphertext (e.g. `pci`, `eu`). The role is folded into the key derivation, so the value can only be decrypted by presenting the **same role** — the policy travels *with the data*, not just at the gateway.

```bash theme={"dark"}
curl ... -d '{ "data": "4242...", "role": "pci" }'   # encrypt under role "pci"
curl ... -d '{ "data": "kc:...:$", "role": "pci" }'  # must pass role "pci" to decrypt
```

## Client-side reveal without an API key

Browsers and agents should never hold an API key. To let a frontend reveal **one** value, your backend mints a **single-use, payload-pinned capability token** and hands it over:

```bash theme={"dark"}
# Backend (API key): mint a token bound to exactly one ciphertext.
curl -X POST https://api.knoxcall.com/v1/client-tokens \
  -H "Authorization: Bearer $KC_API_KEY" -H "Content-Type: application/json" \
  -d '{ "action": "decrypt", "data": "kc:1:s:...:$", "ttl_seconds": 300 }'
# → { "token": "kct_...", "expires_at": "...", "action": "decrypt" }

# Browser (no API key): exchange the token ONCE for the plaintext.
curl -X POST https://api.knoxcall.com/v1/client/decrypt \
  -H "Authorization: Bearer kct_..." -H "Content-Type: application/json" \
  -d '{ "data": "kc:1:s:...:$" }'
# → { "data": "4242424242424242" }
```

The token is consumed on first use, expires within minutes, and only matches the exact ciphertext it was minted for. A leak reveals at most that one value, once. The same flow works for vault tokens with `action: "detokenize"` → `POST /v1/client/detokenize`.

## Dual-custody vaults

A [vault](/essentials/vaults/overview) created with `custody_mode: "dual"` issues `kc:` ciphertext as its token and **stores no value at all** — you keep the ciphertext, KnoxCall keeps only the key. A breach of KnoxCall alone leaks nothing, and detokenize is a pure decrypt (no database lookup).

## Learn more

* [Ciphertext format & cryptographic spec](/essentials/encryption/ciphertext-spec) — the exact wire format and algorithms.
* [Encryption threat model](/security/threat-model) — what the design defends against, and the trust boundaries.
