> ## 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.
</Tip>

## 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](/encryption) 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.59 confidential-proxy --kek "$CLIENT_KEK"
npx -p @premai/api-sdk@1.0.59 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>

<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).
</Note>

## 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"`.
</Warning>

### 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](/guides/openai-compatible-clients) for supported routes, configuration patterns, production controls, and compatibility limits.
</Tip>

```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": "glm-5.2",
    "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: "glm-5.2",
  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="glm-5.2",
    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": "glm-5.2",
    "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": "glm-5.2",
    "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](/guides/anthropic-compatible-clients) for translation behavior, model substitution, token estimates, tool handling, and known limits.
</Tip>

### Agent harnesses

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

<CardGroup cols={2}>
  <Card title="OpenCode" icon="terminal" href="/guides/opencode" arrow="true">
    Configure an OpenAI-compatible provider in a project.
  </Card>

  <Card title="Claude Code" icon="terminal" href="/guides/claude-code" arrow="true">
    Launch Claude Code through the bundled Anthropic adapter.
  </Card>

  <Card title="OpenClaw" icon="terminal" href="/guides/openclaw" arrow="true">
    Configure a custom Chat Completions provider.
  </Card>

  <Card title="Hermes Agent" icon="terminal" href="/guides/hermes" arrow="true">
    Use a named custom provider with an explicit Chat Completions transport.
  </Card>

  <Card title="Goose" icon="terminal" href="/guides/goose" arrow="true">
    Point the built-in OpenAI provider at the local proxy.
  </Card>

  <Card title="Loupe" icon="desktop" href="/guides/loupe" arrow="true">
    Review the current boundary around Loupe's embedded Claude Code workers.
  </Card>

  <Card title="Cursor compatibility" icon="code" href="/guides/cursor" arrow="true">
    Understand why Cursor's base URL override is not a confidential local path.
  </Card>

  <Card title="Codex CLI compatibility" icon="terminal" href="/guides/codex-cli" arrow="true">
    Review the current Responses API protocol mismatch.
  </Card>
</CardGroup>

### Router alternative

<Badge color="blue">Beta</Badge>

Router is a separate, non-confidential service with a broader current chat-model catalog. It does not use the Confidential Proxy, client KEK, or attestation path.

Use the [Router integrations guide](/router/integrations) for supported Chat Completions harnesses. Router uses `PREM_ROUTER_API_KEY` and `https://router.prem.io/v1`; the Confidential API uses `PREM_API_KEY`, a client KEK, and the local proxy. Their credentials and 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](/guides/claude-microsoft-365) for tenant setup, key custody, network placement, acceptance tests, and security boundaries.
</Tip>

```bash theme={"system"}
confidential-proxy \
  --host 0.0.0.0 --port 8787 \
  --compat anthropic \
  --kek "$CLIENT_KEK" \
  --default-model glm-5.2 \
  --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.
</Note>

## 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        |

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="status">
    The `status` command checks if the process is alive and if the HTTP endpoint is reachable.
  </Step>
</Steps>

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

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/quickstart" arrow="true">
    The step-by-step guide to get your first request working.
  </Card>

  <Card title="Developer Experience" icon="code" href="/developer-experience" arrow="true">
    The two ways to integrate: the TypeScript SDK and the Confidential Proxy.
  </Card>

  <Card title="Chat completions" icon="comments" href="/api-reference/chat-completions" arrow="true">
    The chat API in detail, with streaming and vision payloads.
  </Card>

  <Card title="Encryption" icon="shield-halved" href="/encryption" arrow="true">
    The key exchange and the end-to-end encryption in detail.
  </Card>

  <Card title="Agents & Automation" icon="robot" href="/agents" arrow="true">
    Running the proxy behind an unattended agent or automation? Start here.
  </Card>

  <Card title="OpenCode" icon="terminal" href="/guides/opencode" arrow="true">
    Connect OpenCode to the encrypted OpenAI-compatible route.
  </Card>

  <Card title="Claude Code" icon="terminal" href="/guides/claude-code" arrow="true">
    Launch Claude Code through the encrypted Anthropic-compatible route.
  </Card>

  <Card title="OpenAI-compatible clients" icon="code" href="/guides/openai-compatible-clients" arrow="true">
    Connect existing OpenAI SDKs and applications.
  </Card>

  <Card title="Anthropic-compatible clients" icon="comments" href="/guides/anthropic-compatible-clients" arrow="true">
    Use the Messages API shape with explicit compatibility limits.
  </Card>

  <Card title="Claude for Microsoft 365" icon="building" href="/guides/claude-microsoft-365" arrow="true">
    Deploy the proxy as a Microsoft 365 add-in gateway.
  </Card>
</CardGroup>

<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](/guides/claude-code) for the exact environment variables, model picker, stop command, and plaintext boundary.
</Note>
