> For the complete documentation index, see [llms.txt](https://docs.trezalabs.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trezalabs.com/ai-gateway/quickstart.md).

# Quickstart

Send your first PII-redacted LLM request through the Treza AI Control Plane. You'll create an API key, configure a proxy, point your OpenAI client at Treza, and check the audit log.

### Prerequisites

* A Treza account — sign in at [trezalabs.com](https://trezalabs.com/) (email sign-in; the Starter plan is free)
* An API key from your LLM provider (e.g. an OpenAI `sk-...` key)

### 1. Create a Treza API key

In the dashboard, go to **API Keys** and create a key with the `redact:proxy` scope. Add `redact:run` and `redact:log` if you also want the standalone redaction and log endpoints.

{% hint style="warning" %}
The key (`treza_live_...`) is shown **once** at creation. Store it in a secrets manager — you'll send it as the `Authorization: Bearer` header on every request.
{% endhint %}

### 2. Create a proxy

Go to **Control Plane** in the dashboard and create a proxy:

1. Choose the upstream provider (OpenAI on Starter; Azure OpenAI, Anthropic, or a custom endpoint on Pro+).
2. Paste your upstream provider key. It is envelope-encrypted with KMS at rest, never returned by any API, and used server-side — so your application never needs to handle the provider key again.
3. Copy the proxy id (`proxy_...`).

{% hint style="info" %}
Don't want Treza to store your provider key? Leave it off the proxy and pass it per-request in the `x-model-key` header instead.
{% endhint %}

### 3. Point your client at Treza

The proxy endpoint is OpenAI-compatible, so existing SDKs work with a base-URL change.

**curl**

```bash
curl https://trezalabs.com/api/redact/chat/completions \
  -H "Authorization: Bearer $TREZA_API_KEY" \
  -H "x-treza-proxy: proxy_1718039482_ab12cd34e" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      { "role": "user", "content": "Draft a reply to jane.doe@acme.com confirming her SSN 123-45-6789 was updated." }
    ]
  }'
```

The upstream provider receives the redacted prompt:

```
Draft a reply to [EMAIL_1] confirming her SSN [SSN_1] was updated.
```

**TypeScript (OpenAI SDK)**

```typescript
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.TREZA_API_KEY,                  // treza_live_...
  baseURL: 'https://trezalabs.com/api/redact',    // SDK appends /chat/completions
  defaultHeaders: { 'x-treza-proxy': 'proxy_1718039482_ab12cd34e' },
});

const completion = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [
    { role: 'user', content: 'Draft a reply to jane.doe@acme.com confirming her SSN 123-45-6789 was updated.' },
  ],
});

console.log(completion.choices[0].message.content);
```

**Python (OpenAI SDK)**

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["TREZA_API_KEY"],                 # treza_live_...
    base_url="https://trezalabs.com/api/redact",     # SDK appends /chat/completions
    default_headers={"x-treza-proxy": "proxy_1718039482_ab12cd34e"},
)

completion = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Draft a reply to jane.doe@acme.com confirming her SSN 123-45-6789 was updated."},
    ],
)

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

{% hint style="info" %}
**Streaming is supported.** Set `stream: true` and the proxy forwards the upstream provider's Server-Sent Events stream straight through, so token-by-token output works with the standard OpenAI SDKs. Treza never rewrites the response body — placeholders are rehydrated client-side from the `x-treza-rehydration` map, which is sent as a response header before the first token. Because a placeholder can be split across SSE chunks, rehydrate against the accumulated text rather than individual deltas.
{% endhint %}

### 4. Inspect the response

Every proxied response carries Treza headers:

| Header                | Meaning                                                               |
| --------------------- | --------------------------------------------------------------------- |
| `x-treza-request-id`  | Unique id for this redaction request (matches the audit log)          |
| `x-treza-mode`        | `standard` (managed software redaction) or `tee` (Enterprise enclave) |
| `x-treza-rehydration` | Placeholder → original map (only when requested, see below)           |

If the model's reply references placeholders, request the rehydration map and restore values client-side:

```bash
curl -i https://trezalabs.com/api/redact/chat/completions \
  -H "Authorization: Bearer $TREZA_API_KEY" \
  -H "x-treza-proxy: proxy_1718039482_ab12cd34e" \
  -H "x-treza-rehydrate: 1" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Reply to jane.doe@acme.com"}]}'

# Response header:
# x-treza-rehydration: {"[EMAIL_1]":"jane.doe@acme.com"}
```

```typescript
const { data, response } = await client.chat.completions
  .create(
    { model: 'gpt-4o-mini', messages },
    { headers: { 'x-treza-rehydrate': '1' } },
  )
  .withResponse();

const map: Record<string, string> = JSON.parse(
  response.headers.get('x-treza-rehydration') ?? '{}',
);
let text = data.choices[0].message.content ?? '';
for (const [placeholder, original] of Object.entries(map)) {
  text = text.split(placeholder).join(original);
}
```

### 5. Try redaction without forwarding

To see what the pipeline detects — without calling any upstream and without using your request quota — use `POST /api/redact/run` (requires the `redact:run` scope):

```bash
curl https://trezalabs.com/api/redact/run \
  -H "Authorization: Bearer $TREZA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Call John Smith at (555) 123-4567 about card 4111 1111 1111 1111"}'
```

```json
{
  "redacted": "Call John Smith at [PHONE_1] about card [CC_1]",
  "entities": [
    { "type": "PHONE", "placeholder": "[PHONE_1]", "start": 19, "end": 28 },
    { "type": "CC", "placeholder": "[CC_1]", "start": 40, "end": 46 }
  ],
  "requestId": "req_lx2k9a_1f3b7c2d",
  "mode": "standard",
  "modelVersion": "...",
  "recognizerVersion": "..."
}
```

### 6. View the audit log

Each request (proxied or standalone) writes an audit entry scoped to the API key that made it. Fetch entries with the `redact:log` scope:

```bash
curl "https://trezalabs.com/api/redact/log?limit=20" \
  -H "Authorization: Bearer $TREZA_API_KEY"
```

```json
{
  "entries": [
    {
      "ts": "2026-06-11T18:21:09.412Z",
      "requestId": "req_lx2k9a_1f3b7c2d",
      "source": "proxy",
      "entityCountsByType": { "EMAIL": 1, "SSN": 1 },
      "attestationRef": "shared-software-redaction",
      "modelVersion": "...",
      "recognizerVersion": "..."
    }
  ]
}
```

Query parameters: `limit` (1–500, default 20) and `since` (ISO timestamp). Audit entries contain entity **counts by type** — never the redacted values themselves. Request counts and entities-redacted insights are also available in the dashboard under **Usage & insights**.

### Next steps

* [Proxies & Policies](/ai-gateway/proxies-and-policies.md) — multiple providers, pausing proxies, custom policies
* [Usage & Billing](/ai-gateway/usage-and-billing.md) — usage insights, audit export, and how requests are counted
* [Plans & Pricing](/ai-gateway/plans-and-pricing.md) — included volumes and what happens when you hit your limit
* [Attestation](/ai-gateway/attestation.md) — prove redaction ran inside a Treza Enclave (Enterprise)
