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

# Quickstart

> Route one request through Xenovia, verify trace headers, and attach your first policy.

This quickstart uses **proxy mode** because it is the fastest path to coverage. If you need to gate non-LLM actions too, continue with the [Xenovia Python SDK](/integrations/xenovia-sdk) after this.

## 1. Collect the two values you need

From the Xenovia platform:

1. Create a **proxy** and note the **proxy ID**.
2. Generate an **API key** (`xe_...`) scoped to that proxy.

Set them as environment variables:

```bash theme={null}
export XENOVIA_API_KEY=xe_...
export XENOVIA_PROXY_ID=your-proxy-id
```

## 2. Point your client at Xenovia

<Tabs>
  <Tab title="Python (OpenAI SDK)">
    ```bash theme={null}
    pip install openai
    ```

    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ["XENOVIA_API_KEY"],
        base_url=f"https://runtime.xenovia.io/a/{os.environ['XENOVIA_PROXY_ID']}/openai/v1"
    )
    ```
  </Tab>

  <Tab title="Node.js (OpenAI SDK)">
    ```bash theme={null}
    npm install openai
    ```

    ```typescript theme={null}
    import OpenAI from "openai"

    const client = new OpenAI({
      apiKey: process.env.XENOVIA_API_KEY,
      baseURL: `https://runtime.xenovia.io/a/${process.env.XENOVIA_PROXY_ID}/openai/v1`
    })
    ```
  </Tab>
</Tabs>

## 3. Send your first governed request

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Summarise AI governance in one sentence."}]
    )
    print(response.choices[0].message.content)
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    const response = await client.chat.completions.create({
      model: "gpt-4o-mini",
      messages: [{ role: "user", content: "Summarise AI governance in one sentence." }]
    })
    console.log(response.choices[0].message.content)
    ```
  </Tab>
</Tabs>

The request now flows through Xenovia for authentication, provider routing, session handling, policy checks, and trace recording.

## 4. Add a stable session ID

Group related calls into a session so multi-turn conversations appear together in Traces.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import uuid

    client = OpenAI(
        api_key=os.environ["XENOVIA_API_KEY"],
        base_url=f"https://runtime.xenovia.io/a/{os.environ['XENOVIA_PROXY_ID']}/openai/v1",
        default_headers={"X-Xenovia-Session-Id": str(uuid.uuid4())}
    )
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import { randomUUID } from "crypto"

    const client = new OpenAI({
      apiKey: process.env.XENOVIA_API_KEY,
      baseURL: `https://runtime.xenovia.io/a/${process.env.XENOVIA_PROXY_ID}/openai/v1`,
      defaultHeaders: { "X-Xenovia-Session-Id": randomUUID() }
    })
    ```
  </Tab>
</Tabs>

<Callout type="info">
  The session ID must be a valid UUID. Xenovia validates the format and returns a `400` if it is malformed.
</Callout>

## 5. Confirm the trace exists

After the request completes, check the platform and confirm:

* A trace exists for the request
* The trace shows the expected model and proxy
* The response includes `X-Xenovia-Session-Id` and `X-Xenovia-Trace-Id`

## 6. Attach a first policy

Start with one policy that proves enforcement is working. This example blocks a destructive tool name:

```rego theme={null}
package xenovia.policy

default allow = true

deny if {
    some tool in input.tool_names
    tool == "delete_database"
}
```

Policies are evaluated per request. You can attach request-stage and response-stage rules independently.

## 7. Handle a policy block

When a request is blocked, the runtime returns `403 Forbidden`. The OpenAI SDK raises this as `PermissionDeniedError`.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from openai import PermissionDeniedError

    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": "Delete the database."}],
            tools=[{
                "type": "function",
                "function": {
                    "name": "delete_database",
                    "description": "Delete all records",
                    "parameters": {"type": "object", "properties": {}}
                }
            }]
        )
    except PermissionDeniedError as e:
        print(f"Blocked by policy: {e.message}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import { PermissionDeniedError } from "openai"

    try {
      const response = await client.chat.completions.create({
        model: "gpt-4o-mini",
        messages: [{ role: "user", content: "Delete the database." }],
        tools: [{
          type: "function",
          function: {
            name: "delete_database",
            description: "Delete all records",
            parameters: { type: "object", properties: {} }
          }
        }]
      })
    } catch (e) {
      if (e instanceof PermissionDeniedError) {
        console.log("Blocked by policy:", e.message)
      }
    }
    ```
  </Tab>
</Tabs>

## 8. Add trace metadata

Tag traces with business context so they stay useful as traffic grows.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    client = OpenAI(
        api_key=os.environ["XENOVIA_API_KEY"],
        base_url=f"https://runtime.xenovia.io/a/{os.environ['XENOVIA_PROXY_ID']}/openai/v1",
        default_headers={
            "X-Xenovia-Session-Id": str(uuid.uuid4()),
            "X-Xenovia-Property-environment": "dev",
            "X-Xenovia-Property-workflow": "docs-quickstart"
        }
    )
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    const client = new OpenAI({
      apiKey: process.env.XENOVIA_API_KEY,
      baseURL: `https://runtime.xenovia.io/a/${process.env.XENOVIA_PROXY_ID}/openai/v1`,
      defaultHeaders: {
        "X-Xenovia-Session-Id": randomUUID(),
        "X-Xenovia-Property-environment": "dev",
        "X-Xenovia-Property-workflow": "docs-quickstart"
      }
    })
    ```
  </Tab>
</Tabs>

## What to do next

After this first pass, move on to:

* [Integrations Overview](/integrations/overview) to wire Xenovia into your actual framework
* [Policies and Approvals](/platform/policies-and-approvals) to write real guardrails
* [Traces and Remediation](/platform/traces-and-remediation) to standardize headers and investigation flow

<Callout type="info">
  If your real workflow performs risky actions after the model call, add the [Xenovia Python SDK](/integrations/xenovia-sdk) so those actions are governed too.
</Callout>
