> For the complete documentation index, see [llms.txt](https://docs.toolkit.equs.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.toolkit.equs.ai/standards/security-and-privacy/personal-data-and-encryption.md).

# Personal Data and Encryption

What personal data the platform receives, what it stores and for how long, how it is encrypted at rest, and what stays on the Holder's device.

{% hint style="info" %}
**Who this page is for:** security, privacy, and compliance reviewers assessing the platform, and integration teams answering their questions. It covers what personal data the platform receives, what it stores and for how long, how that data is encrypted at rest, and what the Holder's device holds. It goes deeper than the integration guides - if you're choosing a flow, [Choose a Flow (Issuance)](/standards/issuance/choose-a-flow.md) or [Choose a Flow (Presentation)](/standards/presentation/choose-a-flow.md) is the page you want.
{% endhint %}

{% hint style="warning" %}
**This page describes the non-custodial mobile wallet**, which is what you get by default. Keys are generated on the Holder's device and never leave it, and the platform never holds a copy of an issued credential.

A **custodial web wallet** is available on request. There the platform holds the Holder's keys server-side, which means the issued credential is stored server-side too, for as long as the wallet account exists. Three statements on this page do not hold for it: that the signed credential is never written to disk, that credential keys are controlled only by the Holder, and that Flows 2 and 3 leave no personal data at rest. If you are considering a custodial wallet, ask us for its data-handling detail.
{% endhint %}

### The short version ⚡

* **The credential is never stored by the platform.** It is signed and handed to the wallet in the same request. It exists on the Holder's device, under keys only the Holder controls.
* **Most flows store no personal data at all.** Of the six routes through the platform, four write nothing: two issuance flows fetch claim values only at signing, and two presentation flows either bypass the platform or forward the response in flight. The exceptions are [Flow 1: Pre-authorized + push claims](/standards/issuance/flow-1.md) for issuance, which holds your claim values until the Holder collects, and [Flow 2 · Direct Post: Wallet → Platform → Frontend](/standards/presentation/flows-1-and-2.md) for presentation, which holds the Holder's response until you verify it. Both are encrypted, and both are deleted.
* **Everywhere else, personal data only passes through memory.** The Attribute Provider flows fetch claim values at signing; verification decrypts a response to check it. In both cases the values are used within the request and never written.
* **What the platform keeps permanently is pseudonymous.** The Issuance Result and the Revocation Registry contain no personal data, only your own opaque user ID and anonymized indices, and a record of what was asked.

### Data classes 🗂️

Everything the platform touches falls into one of four classes. They are used in the tables and diagrams on this page; the integration guides describe data in plain words instead of classifying it.

| Class            | Meaning                                                                 | Examples                                            |
| ---------------- | ----------------------------------------------------------------------- | --------------------------------------------------- |
| **Public**       | Safe to publish                                                         | Credential Offers, the Revocation Registry, schemas |
| **Pseudonymous** | No PII in itself, but tied to an identifier you can resolve to a person | Issuance Results, your user ID                      |
| **PII**          | Personal data about the Holder                                          | Claim values, the Holder's email address            |
| **Transient**    | No PII, and short-lived by design                                       | `tx_code`                                           |

### Keys and encryption 🔐

Three key types are involved. The distinction matters because it determines who can decrypt what.

| Key                     | Protects                                | Held by                                                                                                                      |
| ----------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **Holder keys**         | The credential on the device            | The Holder. Hardware-bound where the wallet supports it - Secure Enclave or StrongBox                                        |
| **Per-Tenant KEK**      | Everything personal the platform writes | The platform's KMS, scoped to your Tenant. A *key encryption key* - it wraps other keys rather than encrypting data directly |
| **Platform master key** | Non-personal platform records           | The platform's KMS                                                                                                           |

Personal data is protected with **envelope encryption**: each record gets its own **DEK** (*data encryption key*), and that DEK is wrapped by your Tenant's KEK. A compromised key for one record doesn't expose any other record, and nothing personal belonging to your Tenant is decryptable with another Tenant's keys.

Non-personal records - Issuance Results, the Revocation Registry - are protected with the platform master key rather than your KEK, because they are not Tenant-confidential.

Credentials are signed with your **Issuer Key** and presentation requests with your **Verifier Key**, both held in the KMS and created for you during setup. The platform never possesses Holder keys.

### What is stored, and for how long ⏳

<table data-search="false"><thead><tr><th>Data</th><th width="150">Class</th><th>Storage/encryption at rest</th><th>Retention</th></tr></thead><tbody><tr><td><strong>Claim values</strong> (Flow 1 only)</td><td>PII</td><td>Per-record DEK under your Tenant KEK</td><td>Until the credential is issued, or 5 days if never collected</td></tr><tr><td><strong>Holder's email</strong> (Flow 1, when the platform emails the code)</td><td>PII</td><td>Per-record DEK under your Tenant KEK</td><td>Until the credential is issued, or 5 days if never collected</td></tr><tr><td><strong><code>tx_code</code></strong></td><td>Transient</td><td>Platform master key</td><td>3 minutes. Can be regenerated</td></tr><tr><td><strong>Issuance Result</strong></td><td>Pseudonymous</td><td>Platform master key</td><td>Kept</td></tr><tr><td><strong>Revocation Registry</strong></td><td>Public</td><td>Platform master key</td><td>Kept</td></tr><tr><td><strong>Signed credential</strong></td><td>PII</td><td><strong>Never written to disk</strong></td><td>Not applicable</td></tr><tr><td><strong><code>vp_token</code></strong> (presentation Flow 2 only)</td><td>PII</td><td>Per-record DEK under your Tenant KEK</td><td>Until you verify it, or 5 minutes if never verified</td></tr><tr><td><strong>Verification Result</strong></td><td>Pseudonymous</td><td>Platform master key</td><td>Kept</td></tr></tbody></table>

#### What an Issuance Result contains

The issuer ID, the schema ID, your own opaque user ID, the date, the status, and the revocation index. No claim values, no contact details, nothing that identifies the Holder to anyone but you.

#### What a Verification Result contains

The request id, the Verifier that asked, the status, the timestamps, and the query the wallet was given. No claim values: those are returned to you at verification and not kept.

### PII at rest, by flow 💾

#### Issuance

| Flow                                      | Personal data written to platform storage                                                                        |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Flow 1 · Pre-authorized + push claims** | Claim values, plus the Holder's email when the platform emails the code. Encrypted, bounded window, then deleted |
| **Flow 2 · Authorization + pull claims**  | None. Claim values pass through memory at signing time and are never written                                     |
| **Flow 3 · Pre-authorized + pull claims** | None. The trigger carries your user ID only, and claim values pass through memory at signing time                |

Flows 2 and 3 achieve this the same way: the platform holds no claim values because it asks you for them at the moment of signing, and the answer is used and discarded within the request.

Flow 3 also avoids holding a contact detail. Where the wallet fetches the code it identifies the Holder by your user ID, so no email is needed; otherwise the `tx_code` is returned to you and you deliver it, which means the platform never sees an address.

#### Presentation

| Flow                                                   | Personal data written to platform storage                                                                       |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| **Flow 1 · DC API: Wallet → Frontend**                 | None. The response goes from the wallet to your page, and the platform is never on the path                     |
| **Flow 2 · Direct Post: Wallet → Platform → Frontend** | The `vp_token`, encrypted under your Tenant key. Deleted when you verify it, or after 5 minutes if you never do |
| **Flow 3 · Direct Post: Wallet → Platform → Backend**  | None. The response is forwarded to your endpoint in flight, never written                                       |

### Where personal data travels 🧭

#### Issuance

**Flow 1 · Pre-authorized + push claims**

```mermaid
flowchart LR
    T["Your back end"] -->|"claim values, Holder email<br/>PII"| D["Platform"]
    D --> DB[("claim values + email at rest<br/>PII · per-record DEK under your KEK<br/>deleted on issuance or after 5 days")]
    D -->|"Offer, public · tx_code, transient"| W["Wallet"]
    D -->|"signed credential, PII<br/>never written to disk"| W
    W --> H["Holder's phone<br/>holder-controlled keys"]
    style T fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style D fill:#fff4e5,stroke:#f9ab00,color:#1a1a1a
    style W fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style H fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style DB fill:#fce8e6,stroke:#ea4335,color:#1a1a1a
```

**Flow 2 · Authorization + pull claims**

```mermaid
flowchart LR
    U["Holder starts<br/>in the wallet or on your site"] --> W["Wallet"]
    W -->|"authorization code"| D["Platform"]
    D -->|"claims for this Holder?"| AP["Your Attribute Provider"]
    AP -->|"claim values, PII<br/>in memory only, never written"| D
    D -->|"signed credential, PII<br/>never written to disk"| W
    W --> H["Holder's phone<br/>holder-controlled keys"]
    style U fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style AP fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style D fill:#fff4e5,stroke:#f9ab00,color:#1a1a1a
    style W fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style H fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
```

**Flow 3 · Pre-authorized + pull claims**

```mermaid
flowchart LR
    T["Your back end"] -->|"user ID only<br/>pseudonymous, no claim values"| D["Platform"]
    D -->|"Offer, public · tx_code, transient"| W["Wallet"]
    D -->|"claims for this user ID?"| AP["Your Attribute Provider"]
    AP -->|"claim values, PII<br/>in memory only, never written"| D
    D -->|"signed credential, PII<br/>never written to disk"| W
    W --> H["Holder's phone<br/>holder-controlled keys"]
    style T fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style AP fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style D fill:#fff4e5,stroke:#f9ab00,color:#1a1a1a
    style W fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style H fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
```

Only Flow 1 has a storage node. That is the whole difference.

#### Presentation

**Flow 1 · DC API: Wallet → Frontend**

```mermaid
flowchart LR
    W["Wallet"] -->|"vp_token, PII<br/>encrypted for your Tenant"| FE["Your page<br/>relays it, cannot read it"]
    FE --> BE["Your back end"]
    BE -->|"verify"| D["Platform"]
    D -->|"claim values, PII<br/>in memory only"| BE
    style W fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style FE fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style BE fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style D fill:#fff4e5,stroke:#f9ab00,color:#1a1a1a
```

**Flow 2 · Direct Post: Wallet → Platform → Frontend**

```mermaid
flowchart LR
    W["Wallet"] -->|"vp_token, PII"| D["Platform"]
    D --> DB[("vp_token at rest<br/>PII · per-record DEK under your KEK<br/>deleted when you verify it,<br/>or after 5 minutes")]
    D -->|"you collect it, still encrypted"| FE["Your page"]
    FE --> BE["Your back end"]
    BE -->|"verify"| D
    style W fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style FE fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style BE fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style D fill:#fff4e5,stroke:#f9ab00,color:#1a1a1a
    style DB fill:#fce8e6,stroke:#ea4335,color:#1a1a1a
```

**Flow 3 · Direct Post: Wallet → Platform → Backend**

```mermaid
flowchart LR
    W["Wallet"] -->|"vp_token, PII"| D["Platform"]
    D -->|"forwarded in flight<br/>never written"| BE["Your endpoint"]
    BE -->|"verify"| D
    D -->|"claim values, PII<br/>in memory only"| BE
    style W fill:#e6f4ea,stroke:#34a853,color:#1a1a1a
    style BE fill:#e8f0fe,stroke:#4285f4,color:#1a1a1a
    style D fill:#fff4e5,stroke:#f9ab00,color:#1a1a1a
```

### On the Holder's device 📱

The credential lives in the wallet under keys only the Holder controls. Where the wallet supports it, those keys are hardware-bound - Secure Enclave on iOS, StrongBox on Android - so the private key cannot be exported even by the Holder.

The platform cannot produce a copy of an issued credential, for you or for anyone else. If a Holder loses their device, the credential is gone and must be reissued.

### Revocation 🚫

Revocation touches no personal data. You call the platform with your own user ID; the platform updates the Revocation Registry and marks the Issuance Result revoked. The registry holds anonymized revocation indices and nothing else, which is what allows it to be public - a verifier can check whether a credential is still valid without learning who it belongs to, and without contacting you.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.toolkit.equs.ai/standards/security-and-privacy/personal-data-and-encryption.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
