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

# Personal servers

> The user's access engine — client-side today, with a future user-controlled compute environment. API surface, hosting, and grant enforcement.

A **Personal Server** is the user's access engine: it holds (a reference to) the user's data and decides, per request, whether to release a scope to a builder. It is where [grants](/protocol-reference/grants-permissions) are enforced, data is served, and access is logged. It is the only protocol component that works with plaintext data.

It runs the **[Vana SDK](/applications/context-gateway#the-sdk)** — encryption, decryption, permission checks, and identity — so the trust-bearing logic executes under the user's control, not on a builder's servers. Today the Personal Server is **client-side**: it runs on the user's own device, bundled into the desktop app, or in a browser tab for the web.

<Info>
  A Personal Server is a **protocol participant** — it registers onchain and can act under the scopes the user allows. A Vana app (the desktop app, or a web app) is a **client** that bundles and controls a Personal Server, but is not itself a protocol participant. Think of it like email: the app is your mail client, the Personal Server is your mail server.
</Info>

## What every Personal Server does

* **Syncs data** from the user's connected sources into their own storage, organized by [scope](/protocol-reference/scopes-schemas)
* **Serves data** to builders who hold a valid [grant](/protocol-reference/grants-permissions), scope by scope, over an authenticated API
* **Encrypts data** before uploading to [storage backends](/protocol-reference/storage-encryption)
* **Validates grants** on every request — registered grantee, unrevoked, unexpired, scope covered, and (where fee gating is enabled) fee paid
* **Exposes an MCP interface** so agents can work with the user's data under the same grant permissions — bounding *what* an agent may access (see [Agents](/applications/agents))
* **Keeps an access log** the user can review

Today the Personal Server is the entity that decrypts and returns a requested scope to a grantee. With [Protocol-Governed Encryption (PGE)](/protocol-reference/encryption-pge) the grantee receives a per-request key and decrypts the data itself; the grant interface a builder integrates with is the same regardless of where decryption happens.

## Forms

| Form               | Where it runs                                                                               | Storage                | Status |
| ------------------ | ------------------------------------------------------------------------------------------- | ---------------------- | ------ |
| **Desktop (Full)** | Bundled in the desktop app, running locally on the user's machine                           | Filesystem             | Live   |
| **Web (Lite)**     | A separate browser tab on the user's device                                                 | In-browser (IndexedDB) | Live   |
| **User compute**   | A compute environment the user fully controls (see [below](#bring-your-own-compute-future)) | Filesystem             | Future |

The desktop and web forms share one codebase and one SDK; they differ only in where they run and how they store data. Both keep the data and keys on the client. The desktop form keeps keys in the OS filesystem; the Web (Lite) form keeps them in the browser (IndexedDB) for zero-install convenience.

## Registration

Every Personal Server must be registered onchain via the `DataPortabilityServers` contract. Registration records the server's address, public key, and URL. Users then **trust** a server to act on their behalf.

The [DP RPC](/protocol-reference/dp-rpc) provides signature-based registration so a Vana app can register a server without the user sending an onchain transaction directly:

```
POST /v1/servers
```

See [Identity](/protocol-reference/identity) for the full registration flow and the `DataPortabilityServers` contract interface.

## API

The Personal Server exposes a versioned REST API under `/v1`.

### Data endpoints

| Method   | Path                        | Description                                        |
| -------- | --------------------------- | -------------------------------------------------- |
| `POST`   | `/v1/data/{scope}`          | Create a new data document for a scope             |
| `GET`    | `/v1/data`                  | List available scopes and latest version metadata  |
| `GET`    | `/v1/data/{scope}`          | Read data for a scope (latest or specific version) |
| `GET`    | `/v1/data/{scope}/versions` | List available versions (metadata only)            |
| `DELETE` | `/v1/data/{scope}`          | Delete data for a scope (user-only)                |

### Grant endpoints

| Method | Path                | Description                    |
| ------ | ------------------- | ------------------------------ |
| `GET`  | `/v1/grants`        | List all grants for this user  |
| `POST` | `/v1/grants`        | Create a new grant (user-only) |
| `POST` | `/v1/grants/verify` | Verify a grant signature       |

### Other endpoints

| Method | Path              | Description                |
| ------ | ----------------- | -------------------------- |
| `GET`  | `/v1/access-logs` | Get access log history     |
| `GET`  | `/health`         | Health check (unversioned) |

### Query parameters for `GET /v1/data`

| Parameter     | Description                               |
| ------------- | ----------------------------------------- |
| `scopePrefix` | Filter by scope prefix (e.g. `instagram`) |
| `limit`       | Maximum number of results                 |
| `offset`      | Pagination offset                         |

### Query parameters for `GET /v1/data/{scope}`

| Parameter | Description                                                            |
| --------- | ---------------------------------------------------------------------- |
| `fileId`  | Return a specific version by DataRegistry fileId                       |
| `at`      | Return the version closest to this ISO 8601 timestamp (closest ≤ `at`) |

If neither parameter is provided, the latest version by `collectedAt` is returned.

### Write flow (`POST /v1/data/{scope}`)

When a data document is written:

1. Look up `schemaId` for the scope via the [DP RPC](/protocol-reference/dp-rpc)
2. Validate the request body against the schema
3. Generate a `collectedAt` timestamp (UTC)
4. Construct the [data file envelope](/protocol-reference/scopes-schemas#data-file-format) with schema URL, version, scope, and timestamp
5. Store locally in `~/.vana/data/{scope}/{collectedAt}.json`
6. Return `201 Created` immediately
7. Asynchronously: encrypt with the [scope key](/protocol-reference/storage-encryption#key-derivation), upload to the storage backend, and register in the DataRegistry

## Builder data access

Builders read data from the Personal Server using signed HTTP requests. Every builder request must include an `Authorization: Web3Signed` header.

### Web3Signed authorization

```
Authorization: Web3Signed <base64url(json)>.<signature>
```

The payload is a JSON object with keys sorted alphabetically:

```json theme={null}
{
  "aud": "https://user-abc.server.vana.com",
  "bodyHash": "",
  "exp": 1737500300,
  "grantId": "0x...",
  "iat": 1737500000,
  "method": "GET",
  "uri": "/data/instagram.profile"
}
```

| Field      | Description                                              |
| ---------- | -------------------------------------------------------- |
| `aud`      | Personal Server origin (must match)                      |
| `method`   | HTTP method of the request                               |
| `uri`      | Request path and query string                            |
| `bodyHash` | Hash of request body (empty string for GET)              |
| `iat`      | Issued-at timestamp (Unix seconds)                       |
| `exp`      | Expiration timestamp (Unix seconds)                      |
| `grantId`  | Onchain `permissionId` — **required** for raw data reads |

**Signing:** The JSON is canonicalized (keys sorted alphabetically), then base64url-encoded (no padding). The `signature` is an EIP-191 signature over the ASCII bytes of the base64url string.

<Tip>In practice a builder does not build these requests by hand — the [Vana SDK](/applications/context-gateway#the-sdk) signs them and handles the paid-read challenge. See the [Build a Vana App](/build-a-vana-app) guide.</Tip>

### Verification

When the Personal Server receives a builder request, it:

1. Recovers the signer address from the `Authorization` header
2. Verifies the signer is a registered builder onchain
3. Checks `aud` matches the server's own origin
4. Checks `method` and `uri` match the actual request
5. Validates `iat`/`exp` are within the allowed skew window (e.g. 5 minutes)
6. For data reads: verifies `grantId` exists onchain and the signer matches the grantee
7. Confirms the requested scope is within the granted scopes
8. Where fee gating is enabled, confirms the grant's fee shows as paid (see [Payments & fees](/protocol-reference/payments-fees))
9. Logs the access

### Access control summary

| Endpoint                               | Who can call                     |
| -------------------------------------- | -------------------------------- |
| `POST /v1/data/{scope}`                | User only                        |
| `GET /v1/data`, `GET /v1/data/{scope}` | User or builder with valid grant |
| `GET /v1/data/{scope}/versions`        | User or builder with valid grant |
| `DELETE /v1/data/{scope}`              | User only                        |
| `POST /v1/grants`, `GET /v1/grants`    | User only                        |
| `GET /v1/access-logs`                  | User only                        |

## Reachability

A client-side Personal Server must be reachable from the internet for a builder to read from it. A **desktop-bundled** server is reachable while the app is open; when the app is closed, builder requests fail until it reopens. To expose it, Vana provides **FRP tunneling** (Fast Reverse Proxy): the app connects to `proxy.server.vana.org` and receives a public URL at `{userId}.server.vana.org` with automatic TLS. A **self-hosted** server (advanced users, run as a Docker container on their own infrastructure) controls its own URL and uptime.

## Bring your own compute (future)

The forthcoming addition is **bring your own compute**: an option to run your Personal Server in a dedicated compute environment instead of on your own device — so a web user gets an always-available Personal Server without keeping a tab open or installing the desktop app.

This is one of the products **Open Data Labs will offer**: a compute environment **designed so that the user controls it and only the user can see the data**. Data stays encrypted inside the environment, and the intended guarantee is that no one else — including ODL, which provides the environment — can see what runs in it or read the data. This rests on hardware-attested execution and [PGE](/protocol-reference/encryption-pge), both in active development.

```mermaid theme={null}
flowchart TB
    user["user"]:::sdk -->|controls| env["user-controlled compute environment<br/>(ODL product — only the user<br/>can see the data; encrypted inside)"]:::sdk
    env -->|runs| ps["Personal Server + Vana SDK"]:::sdk
    ps -->|serves scoped data on a valid grant| builders["builders"]:::neutral

    classDef sdk fill:#FFF3D1,stroke:#E6A700,color:#5c4400;
    classDef neutral fill:#EEF1F5,stroke:#9AA4B2,color:#1f2937;
```

<Info>**Status.** Live: the **client-side** Personal Server — bundled in the desktop app and running in a browser tab for the web, on a single SDK. Coming: **bring your own compute**, a user-controlled compute environment (an ODL product) where only the user can see the encrypted data.</Info>

## Sync

When a user has multiple Personal Server instances, they stay synchronized through the storage backend and Data Registry. See [Storage & Encryption — Data sync](/protocol-reference/storage-encryption#data-sync) for the full sync model.

## Local data hierarchy

Personal Server implementations that use a filesystem store the same directory layout:

```
~/.vana/
├── data/                       # Decrypted user data
│   ├── instagram/
│   │   ├── profile/
│   │   │   └── 2026-01-21T10-00-00Z.json
│   │   ├── posts/
│   │   └── likes/
│   ├── chatgpt/
│   │   └── conversations/
│   └── youtube/
│       ├── watch_history/
│       └── subscriptions/
├── logs/                       # Access logs (JSON lines, daily rotation)
│   └── access-2026-01-21.log
├── index.db                    # Local registry index (SQLite)
└── server.json                 # Server configuration
```

Files are named `{YYYY-MM-DDTHH-mm-ssZ}.json` using the `collectedAt` timestamp.

## Related

* [Scopes & Schemas](/protocol-reference/scopes-schemas) — Data taxonomy and file format
* [Storage & Encryption](/protocol-reference/storage-encryption) — Key derivation, encryption, and storage backends
* [Encryption & PGE](/protocol-reference/encryption-pge) — How decryption is governed, today and with PGE
* [Grants & Permissions](/protocol-reference/grants-permissions) — How builders get access to data
* [Identity](/protocol-reference/identity) — Server registration and the `DataPortabilityServers` contract
* [Agents](/applications/agents) — The MCP interface and the access log
