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

# Chat Completions API

> Connect to any Digital Twin using the OpenAI SDK — minimal setup, full compatibility

Pria exposes an **OpenAI-compatible Chat Completions API** that lets you interact with any Digital Twin using the standard OpenAI client libraries. If your application already uses the OpenAI SDK, connecting to a Praxis Digital Twin requires just three changes: the **base URL**, the **model ID**, and an **authentication header**.

<Tip>Estimated setup time: **under 5 minutes** if you already have a Praxis account and a Digital Twin configured.</Tip>

***

## How It Works

<CardGroup cols={3}>
  <Card title="Point" icon="plug">
    Set the OpenAI client's `base_url` to your Praxis Chat Completions endpoint.
  </Card>

  <Card title="Authenticate" icon="key">
    Pass your Praxis JWT via the `x-access-token` header to identify the user session.
  </Card>

  <Card title="Chat" icon="comments">
    Use your **Digital Twin's Public ID** as the `model` parameter — that's it.
  </Card>
</CardGroup>

***

## Prerequisites

Before you begin, make sure you have:

* **A Praxis AI account** with access to at least one Digital Twin
* **The Digital Twin's Public ID** (a UUID like `e455529a-4f51-479e-94fc-bbebb41d19a1`) — found in your instance's administration panel
* **A valid Praxis JWT token** (`x-access-token`) — obtained when a user authenticates with Praxis (see [Authentication](#authentication))
* **Chat Completions enabled on the Digital Twin** — this integration is **off by default**; an administrator must turn it on for the instance

<Note>The Chat Completions endpoint is part of the Pria platform itself — the base URL is your Pria server's `/api/ai` path (e.g. `https://pria.praxislxp.com/api/ai`). It is disabled per Digital Twin by default; if requests return `403 chat_completion_disabled`, ask the instance administrator to enable the Chat Completions endpoint in the instance configuration.</Note>

***

## Quick Start

<Steps>
  <Step title="Install the OpenAI SDK">
    <CodeGroup>
      ```bash Python theme={null}
      pip install openai
      ```

      ```bash Node.js theme={null}
      npm install openai
      ```
    </CodeGroup>
  </Step>

  <Step title="Configure the client">
    Point the SDK to your Praxis endpoint and pass your authentication token.

    <CodeGroup>
      ```python Python theme={null}
      from openai import OpenAI

      client = OpenAI(
          api_key="unused",  # required by SDK, but not used for auth
          base_url="https://pria.praxislxp.com/api/ai",
          default_headers={
              "x-access-token": "your-praxis-jwt-token"
          }
      )
      ```

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

      const client = new OpenAI({
        apiKey: "unused",  // required by SDK, but not used for auth
        baseURL: "https://pria.praxislxp.com/api/ai",
        defaultHeaders: {
          "x-access-token": "your-praxis-jwt-token",
        },
      });
      ```
    </CodeGroup>

    <Info>The `api_key` field is required by the OpenAI SDK but is not used for authentication. Praxis authenticates via the `x-access-token` header. If your deployment also uses API keys, pass it as the `api_key` value instead (see [Authentication](#authentication) below).</Info>
  </Step>

  <Step title="Send a message (streaming)">
    Use your **Digital Twin Public ID** as the `model` parameter, and set `stream=True`.

    <Info>The endpoint **always streams** — responses are delivered as OpenAI-format SSE chunks regardless of the `stream` flag, so use your SDK's streaming mode.</Info>

    <CodeGroup>
      ```python Python theme={null}
      stream = client.chat.completions.create(
          model="e455529a-4f51-479e-94fc-bbebb41d19a1",
          messages=[
              {"role": "user", "content": "Explain your area of expertise."}
          ],
          stream=True
      )

      for chunk in stream:
          content = chunk.choices[0].delta.content
          if content:
              print(content, end="", flush=True)
      ```

      ```typescript TypeScript theme={null}
      const stream = await client.chat.completions.create({
        model: "e455529a-4f51-479e-94fc-bbebb41d19a1",
        messages: [
          { role: "user", content: "Explain your area of expertise." }
        ],
        stream: true,
      });

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

      ```bash cURL theme={null}
      curl -X POST https://pria.praxislxp.com/api/ai/chat/completions \
        -H "Content-Type: application/json" \
        -H "x-access-token: your-praxis-jwt-token" \
        -N \
        -d '{
          "model": "e455529a-4f51-479e-94fc-bbebb41d19a1",
          "messages": [
            {"role": "user", "content": "Explain your area of expertise."}
          ],
          "stream": true
        }'
      ```
    </CodeGroup>
  </Step>
</Steps>

***

## Authentication

The API supports two authentication methods that can be used independently or together.

### Praxis JWT (primary)

Pass the user's Praxis session token via the `x-access-token` header. This is the primary authentication method — it identifies the user and authorizes access to their Digital Twins.

```
x-access-token: eyJhbGciOiJIUzI1NiIs...
```

<Warning>Chat completions **always require a valid Praxis JWT** in the `x-access-token` header. An API key alone is not sufficient.</Warning>

### Getting a JWT from a personal API key (server-to-server)

For scripts and server-to-server integrations, exchange a [personal API key](/mdx/user-guide/profile-settings/api-keys) (prefixed `pria_`) for a JWT, then pass that JWT in the `x-access-token` header. The raw `pria_…` key is **not** accepted directly — exchange it first:

```bash theme={null}
APIKEY=pria_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
JWT=$(curl -sS -X POST "https://pria.praxislxp.com/api/auth/api-key-signin" \
       -H "x-api-key: $APIKEY" \
       | python -c "import json,sys; print(json.load(sys.stdin)['token'])")
```

```python theme={null}
client = OpenAI(
    api_key="unused",
    base_url="https://pria.praxislxp.com/api/ai",
    default_headers={
        "x-access-token": jwt_from_api_key_exchange
    }
)
```

***

## Context Headers

Optional headers let you pass conversation metadata to the Digital Twin. These enrich the interaction context without affecting authentication.

| Header                           | Type   | Description                                                             | Default                 |
| -------------------------------- | ------ | ----------------------------------------------------------------------- | ----------------------- |
| `x-access-token`                 | string | **Required.** Praxis JWT for user authentication                        | —                       |
| `x-praxis-institution-public-id` | string | Public ID of the target Digital Twin (when the user belongs to several) | User's primary instance |
| `x-praxis-conversation-id`       | string | Numeric conversation/course identifier                                  | `0`                     |
| `x-praxis-conversation-name`     | string | Human-readable conversation or course name                              | `""`                    |
| `x-praxis-assistant-id`          | string | Routes the request to a specific assistant persona                      | `""`                    |
| `x-praxis-timezone`              | string | IANA timezone (e.g. `America/New_York`) for date-aware prompts          | Server default          |

<Info>Context headers are useful when your application manages multiple conversations or needs to target a specific assistant within a Digital Twin.</Info>

<CodeGroup>
  ```python Python theme={null}
  client = OpenAI(
      api_key="unused",
      base_url="https://pria.praxislxp.com/api/ai",
      default_headers={
          "x-access-token": "your-praxis-jwt-token",
          "x-praxis-conversation-id": "48201",
          "x-praxis-conversation-name": "Biology 101 - Fall 2026",
          "x-praxis-assistant-id": "assistant-uuid-here",
      }
  )
  ```

  ```typescript TypeScript theme={null}
  const client = new OpenAI({
    apiKey: "unused",
    baseURL: "https://pria.praxislxp.com/api/ai",
    defaultHeaders: {
      "x-access-token": "your-praxis-jwt-token",
      "x-praxis-conversation-id": "48201",
      "x-praxis-conversation-name": "Biology 101 - Fall 2026",
      "x-praxis-assistant-id": "assistant-uuid-here",
    },
  });
  ```
</CodeGroup>

***

## Message Roles

The API accepts standard OpenAI message roles with the following behavior:

| Role        | Behavior                                                                                                                             |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `user`      | The **last** user message is the active turn sent to the Digital Twin. Earlier `user` messages are replayed as conversation history. |
| `assistant` | Replayed as conversation history alongside earlier user messages.                                                                    |
| `system`    | Ignored — the Digital Twin builds its own system instructions from assistant and instance settings.                                  |
| `tool`      | Accepted in the shape but ignored — tool execution is managed server-side by Pria.                                                   |

<Note>You can send only the current user message (Pria tracks the conversation via `x-praxis-conversation-id`), or pass your own running message array — prior user/assistant turns you include are replayed as history for the active turn.</Note>

***

## Response Format

The endpoint **always streams**. Responses arrive as standard OpenAI SSE chunks:

```
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":1700000000,"model":"e455529a-...","choices":[{"index":0,"delta":{"content":"I cover topics in"},"finish_reason":null}]}

data: [DONE]
```

Read them exactly as you would an OpenAI streaming response — iterate the stream and concatenate `choices[0].delta.content`.

***

## Supported Parameters

| Parameter                                                                          | Supported     | Notes                                                                                                                                                                              |
| ---------------------------------------------------------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`                                                                            | **Yes**       | Informational — the effective model follows the Digital Twin's configuration cascade (assistant override → instance Chat Completions model override → instance conversation model) |
| `messages`                                                                         | **Yes**       | Message array (required)                                                                                                                                                           |
| `stream`                                                                           | Accepted      | The response is always SSE — streaming is forced regardless of this flag                                                                                                           |
| `temperature` / `max_tokens` / `top_p` / `response_format` and other tuning fields | Accepted      | Accepted for SDK compatibility but not forwarded — these settings are managed by the Digital Twin's configuration                                                                  |
| `tools` / `tool_choice`                                                            | Not supported | The Twin's own server-side tools run automatically; client-supplied function calling is not available                                                                              |

<Info>Administrators can set Chat-Completions-specific overrides on the instance — a dedicated model, a max-completion-tokens cap, and a reasoning-effort level (commonly `none` for voice agents) — without affecting the Twin's normal in-app behaviour.</Info>

***

## Error Handling

Errors follow the standard OpenAI error format:

```json theme={null}
{
  "error": {
    "message": "Description of the error",
    "type": "auth_error",
    "param": null,
    "code": "missing_praxis_token"
  }
}
```

### Common Errors

| Status | Code                       | Cause                                                             | Fix                                                                        |
| ------ | -------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------- |
| 401    | `unauthorized`             | Missing, expired, or invalid JWT in `x-access-token`              | Add or refresh the Praxis JWT (exchange your `pria_…` key again if needed) |
| 403    | `chat_completion_disabled` | The Chat Completions endpoint is not enabled for the Digital Twin | Ask the instance administrator to enable it in the instance configuration  |
| 404    | `model_not_found`          | Invalid Digital Twin Public ID                                    | Verify the Public ID in the instance's administration panel                |
| 429    | `rate_limit_exceeded`      | Too many requests                                                 | Reduce request frequency or request a higher limit                         |
| 504    | `timeout`                  | Digital Twin took too long to respond                             | Retry the request                                                          |

***

## Multi-Provider Routing

The Chat Completions API is a **front door to the Pria platform**, not a thin proxy to a single model provider. Behind the URL, Pria selects the underlying provider and model based on the Digital Twin's configuration. As of today, Pria can route to:

| Provider           | Model families                                               |
| ------------------ | ------------------------------------------------------------ |
| **OpenAI**         | GPT‑4o, GPT‑4.1, o‑series reasoning, GPT‑image, GPT‑Realtime |
| **Anthropic**      | Claude 3.5 / 3.7 / 4.x — Sonnet, Opus, Haiku                 |
| **Amazon Bedrock** | Claude, Llama, Titan, Stable Diffusion                       |
| **Google GenAI**   | Gemini 2.x / 3.x — Pro, Flash, Live (Convo Mode)             |
| **Mistral**        | Mistral Large, Voxtral (TTS / STT), Codestral                |
| **xAI**            | Grok 3, Grok 4, Grok 3‑mini (reasoning)                      |

The `model` parameter you pass in the request is the **Digital Twin Public ID** — not a provider model ID. Pria resolves it to the configured underlying model. If the Twin's admin changes the underlying model from Claude to GPT‑4o, your code does not change.

### Per‑Provider Behavioural Differences

Because Pria forwards to many providers, some advanced behaviours are provider‑dependent and respect the Twin's configuration rather than the request payload:

* **Reasoning effort** — accepted for OpenAI o‑series and xAI `grok-3-mini`. Grok 4.x reasons automatically and ignores the parameter.
* **Thinking tokens** — Anthropic Claude 3.7+ and Gemini 2.5+ support extended thinking budgets, configured per Twin.
* **Image generation** — supported by OpenAI (`gpt-image-1`), Bedrock (Stable Diffusion via Stability), Google (Imagen), and xAI (`grok-2-image`). Mistral delegates to OpenAI or Bedrock.
* **Prompt caching** — automatic for Anthropic, OpenAI, and xAI; reported in the response `usage` block when present.
* **Tool calls** — the Digital Twin's server‑side tools (RAG, web search, charts, connectors, MCP) run automatically. Client‑supplied `tools` / `tool_choice` are not forwarded (see [Supported Parameters](#supported-parameters)).

For the full behaviour matrix, see [AI Models](/mdx/admin-guide/ai-models).

### Provider Authentication Errors

When the Twin is configured to use a provider that requires its own credentials (BYOT — Bring Your Own Tokens), errors from the underlying provider are surfaced back to you as standard OpenAI‑style errors:

| Status                            | Likely cause                                                                                                  |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| 401 from chat completions         | Praxis JWT missing or expired                                                                                 |
| 401 with provider name in message | The Twin's underlying provider key (OpenAI, Anthropic, etc.) is missing or invalid — contact the Twin's admin |
| 429                               | Rate limited at the provider level — back off and retry                                                       |
| 5xx with `provider_error`         | Upstream provider is degraded; retry with exponential backoff                                                 |

See [BYOT (Bring Your Own Tokens)](/mdx/introduction/byot) for how Twin admins configure provider keys.

***

## Cost & Credits

Chat completions consume Pria credits, billed by token usage and the underlying provider's price tier. Each response's `usage` block reports `prompt_tokens`, `completion_tokens`, and `total_tokens` — the same fields the OpenAI SDK consumers already read.

* **Cached prompt tokens** (when the provider supports caching) are billed at a discounted rate.
* **Streaming requests** are billed identically to non‑streaming.
* **Embedded RAG retrieval** runs as part of the Digital Twin's response and is included in the credit cost — you do not pay separately for vector search.

For your account's plan and credit balance, see [Plans & Credits](/mdx/introduction/plans-and-credits) and [Credit Management](/mdx/admin-guide/credit-management).

***

## Chat Completions vs. the Pria Runtime API

Pria exposes two complementary APIs. They look similar but behave very differently — choose based on whether you want stateless OpenAI‑style requests or full Pria session semantics.

|                             | **Chat Completions API**                                                                   | **Runtime API**                                                      |
| --------------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| **Shape**                   | OpenAI‑compatible                                                                          | Pria‑native REST + WebSocket                                         |
| **State**                   | Stateless — each call is independent                                                       | Stateful — Pria tracks the user's conversation thread                |
| **History**                 | Last user message is the active turn; earlier messages you include are replayed as history | Pria stores the full thread server‑side                              |
| **RAG / KAG retrieval**     | Runs automatically as part of the response                                                 | Runs automatically as part of the response                           |
| **Tool calls**              | The Twin's tools run server‑side; not exposed to the caller                                | The Twin's tools run server‑side; tool events streamed to the caller |
| **Conversation continuity** | Use `x-praxis-conversation-id` to group calls into a thread                                | Native; each call references a `historyId`                           |
| **Streaming**               | OpenAI SSE format                                                                          | Pria event stream (richer event types)                               |
| **Best for**                | Drop‑in replacement for OpenAI in existing code                                            | Building a full Pria‑powered chat experience from scratch            |

**Rule of thumb:** if your code already uses the OpenAI SDK and you want to point it at Pria with minimal changes, use the Chat Completions API. If you're building a new client from scratch and want access to every Pria capability (per‑message tool events, citations, KAG augmentations, structured memory updates), use the Runtime API.

See the [API Reference](/mdx/api-reference/introduction) for both.

***

## Related

* [API Reference](/mdx/api-reference/introduction) — Full REST API documentation with streaming details
* [AI Models](/mdx/admin-guide/ai-models) — Provider catalog, reasoning effort, thinking, and image generation behaviour per provider
* [API Keys](/mdx/user-guide/profile-settings/api-keys) — Issue and rotate the API keys used to obtain Praxis JWTs
* [BYOT (Bring Your Own Tokens)](/mdx/introduction/byot) — How Twin admins configure per‑provider credentials
* [Plans & Credits](/mdx/introduction/plans-and-credits) — How token usage maps to credits
* [MCP Server](/mdx/integrations/mcp/introduction) — Connect Pria to custom LLM workflows
* [Web SDK](/mdx/integrations/web/introduction) — Embed the full Digital Twin UI in your web app
* [JavaScript SDK](/mdx/sdk/javascript) — Programmatic control of the Pria interface
