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

# Confidential Proxy

> Run a local proxy for supported OpenAI- and Anthropic-compatible routes.
Point a compatible client at the local base URL.


The **Confidential Proxy** is a local termination proxy that comes with [`@premai/api-sdk`](https://www.npmjs.com/package/@premai/api-sdk).
It exposes supported **OpenAI- and Anthropic-compatible** HTTP routes on your machine.

For a supported OpenAI client, set the base URL to `http://127.0.0.1:8787/v1`. Anthropic clients use the same local base URL when the proxy runs in Anthropic mode. In `both` mode, use the separate prefixes documented below.

> [!TIP]
>
> If you use the TypeScript SDK, you do not need the Confidential Proxy.
>
> The SDK encrypts in the same process. Use the Confidential Proxy for other languages and for existing OpenAI or Anthropic codebases.

## How it works

The Confidential Proxy runs on your machine and applies the SDK's client-side encryption. It encrypts the request payload **before** network egress. The Prem API Gateway receives payload ciphertext plus operational metadata. The selected confidential runtime decrypts the request inside its Trusted Execution Environment (TEE).

```mermaid theme={"system"}
flowchart LR
    subgraph Local["Your Machine"]
        A[OpenAI / Anthropic client] -->|"baseURL → 127.0.0.1:8787"| B[confidential-proxy]
        B -->|"encrypt"| C[Encrypted request]
    end

    subgraph Gateway["Prem API Gateway"]
        D[Payload ciphertext and metadata]
    end

    subgraph Enclave["Prem API Enclave (TEE)"]
        E[Decrypt → process → encrypt]
    end

    C --> D --> E
    E --> D
    D -->|Encrypted response| B
    B -->|Decrypted response| A
```

See [Encryption](https://docs.prem.io/encryption.md) for the full cryptographic design: the XWing key exchange, the two-server model, and the threat model.

## Run the server

Run the Confidential Proxy directly with `bunx` or `npx`. No installation is necessary. As an alternative, install it globally:

```bash theme={"system"}
# Run without installing (bun or npm)
bunx -p @premai/api-sdk@1.0.70 confidential-proxy --kek "$CLIENT_KEK"
npx -p @premai/api-sdk@1.0.70 confidential-proxy --kek "$CLIENT_KEK"

# Or install globally, then run (confirm your global bin dir is on your PATH)
npm i -g @premai/api-sdk   # or: bun i -g @premai/api-sdk
confidential-proxy --kek "$CLIENT_KEK"
```

A prebuilt Docker image is available at `ghcr.io/premai-io/confidential-proxy:latest`:

```bash theme={"system"}
docker pull ghcr.io/premai-io/confidential-proxy:latest

# OpenAI-compatible server on port 8787
docker run -p 8787:8787 \
  -e PROXY_URL=... -e ENCLAVE_URL=... \
  ghcr.io/premai-io/confidential-proxy:latest \
  --kek "$CLIENT_KEK"

# Extra arguments go to the CLI
docker run -p 8787:8787 \
  -e PROXY_URL=... -e ENCLAVE_URL=... \
  ghcr.io/premai-io/confidential-proxy:latest \
  --kek "$CLIENT_KEK" --log-level debug
```

The image sets `HOST=0.0.0.0` and `PORT=8787`. You can override these values with environment variables or CLI flags. Use CLI flags for `--compat` and `--tls`. You cannot set these two flags with environment variables.

By default, the server listens on **`http://127.0.0.1:8787`**.

> [!NOTE]
>
> `8787` is the default in `@premai/api-sdk` and in the `confidential-claude` launcher. Port `8000` also works when you start the proxy with `--port 8000` and point every client at the same port. A client configured for `8000` cannot reach a proxy that was started without a port override, because that proxy listens on `8787`.

> [!NOTE]
>
> Set `PROXY_URL` and `ENCLAVE_URL` to the values for your environment. Get the latest values from [`dashboard.prem.io/endpoints.json`](https://dashboard.prem.io/endpoints.json).

## Configuration

Configure the Confidential Proxy with environment variables or CLI flags. Flags have precedence.

### Environment variables

| Variable | Required | Default | Description |
| - | - | - | - |
| `ENCLAVE_URL` | Yes | - | The enclave endpoint that decrypts the data and runs inference |
| `PROXY_URL` | Yes | - | The Prem API Gateway endpoint that routes encrypted payloads |
| `JSON_BODY_LIMIT` | No | `32mb` | The maximum size of the request body |
| `HOST` | No | `127.0.0.1` | The interface to bind |
| `PORT` | No | `8787` | The port to listen on |
| `CONFIDENTIAL_PROXY_LOG_LEVEL` | No | `info` | `error`, `warn`, `info`, `http`, `verbose`, `debug`, or `silly` |
| `PREM_API_KEY` | No | - | A default API key. The proxy uses this key when a client does not send its own key |

> [!WARNING]
>
> Set `PREM_API_KEY` to a default API key. The proxy applies this key when a client does not supply its own key. Each client can also send its own API key with each request. Use `Authorization: Bearer <key>` for OpenAI routes. Use `x-api-key: <key>` for Anthropic routes. The Confidential Proxy keeps one client in memory for each API key.
>
> `CLIENT_KEK` is a separate key. The Confidential Proxy uses it only to wrap encryption keys. It is not an API key. The current CLI does not bind the `CLIENT_KEK` environment variable to the server option. Pass the value explicitly with `--kek "$CLIENT_KEK"`.

### CLI options

All commands accept the same server options:

```bash theme={"system"}
# Bind host / port
confidential-proxy --host 127.0.0.1 --port 8787 --kek "$CLIENT_KEK"

# Override backend endpoints
confidential-proxy --proxy-url https://gateway.prem.io --enclave-url https://conf-engine.prem.io --kek "$CLIENT_KEK"

# Pass the client KEK from the environment
# The value must be 32 bytes encoded as 64 hexadecimal characters.
confidential-proxy --kek "$CLIENT_KEK"

# Raise the JSON body size limit
confidential-proxy --json-body-limit 64mb --kek "$CLIENT_KEK"
```

## Compatibility modes

Use `--compat` to select the API surface:

| Mode | Routes | Description |
| - | - | - |
| `openai` | `/v1/*` | The OpenAI-compatible API only |
| `anthropic` | `/v1/*` | The Anthropic-compatible Messages API only |
| `both` | `/openai/v1/*` and `/anthropic/v1/*` | The two APIs together, each with a separate prefix |

```bash theme={"system"}
# OpenAI only (default surface)
confidential-proxy --compat openai --kek "$CLIENT_KEK"

# Anthropic only
confidential-proxy --compat anthropic --kek "$CLIENT_KEK"

# Both, with custom prefixes
confidential-proxy --compat both --openai-prefix /openai --anthropic-prefix /anthropic --kek "$CLIENT_KEK"
```

In `both` mode, the Confidential Proxy serves the two APIs under separate prefixes. This prevents route conflicts. Set the base URL to `http://127.0.0.1:8787/openai/v1` for OpenAI clients. Set it to `http://127.0.0.1:8787/anthropic/v1` for Anthropic clients. The Anthropic surface translates each Anthropic Messages request into the internal OpenAI-compatible enclave pipeline. It then returns the response as Anthropic SSE events.

## Connect a client

### OpenAI

Set the base URL to `http://127.0.0.1:8787/v1`. If you use `--compat both`, set it to `http://127.0.0.1:8787/openai/v1`. Send your API key as a bearer token:

> [!TIP]
>
> See [OpenAI-compatible clients](https://docs.prem.io/guides/openai-compatible-clients.md) for supported routes, configuration patterns, production controls, and compatibility limits.

```bash theme={"system"}
curl http://127.0.0.1:8787/v1/chat/completions \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash-1017",
    "messages": [{"role": "user", "content": "Hello!"}],
    "stream": false
  }'
```

As an alternative, use the OpenAI SDK in Node.js:

```typescript theme={"system"}
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.PREM_API_KEY!,
  baseURL: "http://127.0.0.1:8787/v1",
});

const stream = await client.chat.completions.create({
  model: "deepseek-v4.1-flash-1017",
  messages: [{ role: "user", content: "Count to 10" }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content || "");
}
```

The same pattern applies to all other languages. This is a Python example:

```python theme={"system"}
from openai import OpenAI

client = OpenAI(
    api_key="your-api-key",
    base_url="http://127.0.0.1:8787/v1",
)

response = client.chat.completions.create(
    model="deepseek-v4.1-flash-1017",
    messages=[{"role": "user", "content": "Hello, privately."}],
)

print(response.choices[0].message.content)
```

### Anthropic

Set the base URL to `http://127.0.0.1:8787/v1`. If you use `--compat both`, set it to `http://127.0.0.1:8787/anthropic/v1`. Authenticate with `x-api-key`. Send the `anthropic-version` header:

```bash theme={"system"}
curl http://127.0.0.1:8787/v1/messages \
  -H "x-api-key: your-api-key" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash-1017",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hello!"}]
  }'
```

Add `"stream": true` for incremental responses:

```bash theme={"system"}
curl -N http://127.0.0.1:8787/v1/messages \
  -H "x-api-key: your-api-key" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash-1017",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Count to 10"}],
    "stream": true
  }'
```

The Anthropic surface supports system prompts, tool use, image inputs, stop sequences, `temperature`, and `top_p`. Streaming responses follow the Anthropic SSE format (`message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta`, `message_stop`).

> [!TIP]
>
> See [Anthropic-compatible clients](https://docs.prem.io/guides/anthropic-compatible-clients.md) for translation behavior, model substitution, token estimates, tool handling, and known limits.

### Agent harnesses

Use a dedicated guide for each harness. The provider schema, protocol selection, tool boundary, and startup command differ.

> [card] [OpenCode](https://docs.prem.io/guides/opencode.md)
>
> Configure an OpenAI-compatible provider in a project.

> [card] [Claude Code](https://docs.prem.io/guides/claude-code.md)
>
> Launch Claude Code through the bundled Anthropic adapter.

> [card] [OpenClaw](https://docs.prem.io/guides/openclaw.md)
>
> Configure a custom Chat Completions provider.

> [card] [Hermes Agent](https://docs.prem.io/guides/hermes.md)
>
> Use a named custom provider with an explicit Chat Completions transport.

> [card] [Goose](https://docs.prem.io/guides/goose.md)
>
> Point the built-in OpenAI provider at the local proxy.

> [card] [Loupe](https://docs.prem.io/guides/loupe.md)
>
> Review the current boundary around Loupe's embedded Claude Code workers.

> [card] [Cursor compatibility](https://docs.prem.io/guides/cursor.md)
>
> Understand why Cursor's base URL override is not a confidential local path.

> [card] [Codex CLI compatibility](https://docs.prem.io/guides/codex-cli.md)
>
> Review the current Responses API protocol mismatch.

### ZDR alternative

ZDR is a separate, non-confidential inference mode. It does not use the Confidential Proxy, client KEK, or attestation path.

Use the [ZDR overview](https://docs.prem.io/zdr/overview.md) for the ZDR setup. ZDR uses `PREM_API_KEY` at `https://gateway.prem.io/openai`; the Confidential API uses `PREM_API_KEY`, a client KEK, and the local proxy. Their data-handling properties are not interchangeable.

### Claude for Microsoft 365

The Confidential Proxy can be the gateway for the [Claude for Microsoft 365 add-in](https://support.claude.com/en/articles/13945233-use-claude-for-microsoft-365-with-third-party-platforms). The add-in uses HTTPS and CORS. Start the proxy with these flags:

> [!TIP]
>
> See [Claude for Microsoft 365](https://docs.prem.io/guides/claude-microsoft-365.md) for tenant setup, key custody, network placement, acceptance tests, and security boundaries.

```bash theme={"system"}
confidential-proxy \
  --host 0.0.0.0 --port 8787 \
  --compat anthropic \
  --kek "$CLIENT_KEK" \
  --default-model deepseek-v4.1-flash-1017 \
  --cors-origin https://pivot.claude.ai \
  --tls --tls-cert ./cert.pem --tls-key ./key.pem
```

> [!NOTE]
>
> The add-in cannot connect to `127.0.0.1` on macOS. macOS prevents cross-origin browser requests to loopback addresses. Run the proxy on a different machine on your network, or use a container with its own network interface. Point the add-in at that hostname.

## Run the proxy as a daemon

By default, the Confidential Proxy runs in the foreground. The CLI can also manage it as a background daemon.

| Command | Description |
| - | - |
| `confidential-proxy` | Run in the foreground, attached to the terminal |
| `confidential-proxy start` | Start the server as a background daemon |
| `confidential-proxy stop` | Stop the daemon with a graceful shutdown |
| `confidential-proxy status` | Show if the daemon runs and is reachable |

**1. start**

The `start` command does these steps:

* It checks for a daemon that is in operation. It does not start a second daemon.
* It spawns itself as a child process. It sends the logs to the log file that you configure.
* It polls the HTTP endpoint until the server is reachable.
* It then exits and the daemon continues to run.

**2. stop**

The `stop` command stops the daemon. It waits a maximum of 5 seconds. If the daemon does not stop, the command stops it immediately.

**3. status**

The `status` command checks if the process is alive and if the HTTP endpoint is reachable.

These options apply to the daemon commands (`start`, `stop`, `status`):

| Option | Default | Description |
| - | - | - |
| `--pid-file` | `<data-dir>/proxy.pid` | A custom path for the PID file |
| `--log-file` | stdout/stderr | The file for the daemon logs (with `start`) |
| `--log-level` | `info` | The log verbosity (`error` … `silly`) |
| `--shutdown-timeout` | `30000` | The maximum time (ms) to wait for requests in progress during a graceful shutdown |

```bash theme={"system"}
# Start in the background, then confirm it's up
confidential-proxy start --compat openai --kek "$CLIENT_KEK"
confidential-proxy status

# Stop it when you're done
confidential-proxy stop
```

## Next steps

> [card] [Quickstart](https://docs.prem.io/quickstart.md)
>
> The step-by-step guide to get your first request working.

> [card] [Developer Experience](https://docs.prem.io/developer-experience.md)
>
> The two ways to integrate: the TypeScript SDK and the Confidential Proxy.

> [card] [Chat completions](https://docs.prem.io/api-reference/chat-completions.md)
>
> The chat API in detail, with streaming and vision payloads.

> [card] [Encryption](https://docs.prem.io/encryption.md)
>
> The key exchange and the end-to-end encryption in detail.

> [card] [Agents & Automation](https://docs.prem.io/agents.md)
>
> Running the proxy behind an unattended agent or automation? Start here.

> [card] [OpenCode](https://docs.prem.io/guides/opencode.md)
>
> Connect OpenCode to the encrypted OpenAI-compatible route.

> [card] [Claude Code](https://docs.prem.io/guides/claude-code.md)
>
> Launch Claude Code through the encrypted Anthropic-compatible route.

> [card] [OpenAI-compatible clients](https://docs.prem.io/guides/openai-compatible-clients.md)
>
> Connect existing OpenAI SDKs and applications.

> [card] [Anthropic-compatible clients](https://docs.prem.io/guides/anthropic-compatible-clients.md)
>
> Use the Messages API shape with explicit compatibility limits.

> [card] [Claude for Microsoft 365](https://docs.prem.io/guides/claude-microsoft-365.md)
>
> Deploy the proxy as a Microsoft 365 add-in gateway.

> [!NOTE]
>
> The SDK also includes `confidential-claude`. It launches Claude Code with the local Anthropic-compatible proxy and forwards Claude Code's arguments. See [Claude Code](https://docs.prem.io/guides/claude-code.md) for the exact environment variables, model picker, stop command, and plaintext boundary.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.