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

# OpenAI Chat Completions

> Drive a Karta agent with the classic OpenAI Chat Completions messages-array shape.

`POST /{org}/{agent}/v1/chat/completions`

Speaks the OpenAI **Chat Completions** shape - the widely-supported
messages-array format. Auth: a [session token](/security/session-tokens) or a
`kt_live_...` key.

## Request

<ParamField body="messages" type="array">
  The conversation so far, as `{ "role": "...", "content": "..." }` items. The
  last user message is what runs. It defaults to empty rather than being
  enforced, so omitting it returns a `200` with empty message content.
</ParamField>

<ParamField body="model" type="string">
  Accepted for OpenAI-client compatibility and echoed back in the response, but
  it does not select the model. The model is configured per agent and org on the
  platform.
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  `true` -> SSE chunks; `false` -> a single completion object.
</ParamField>

## Unary response

```bash theme={null}
curl https://agent.karta.sh/my-org/my-app/v1/chat/completions \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "What roasts do you have?"}]}'
```

```json theme={null}
{
  "id": "chatcmpl_8a1d...",
  "object": "chat.completion",
  "model": "karta",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "We've got Sunrise, Midnight, and Decaf Dusk. " },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 42, "completion_tokens": 28, "total_tokens": 70 }
}
```

## Streaming

```bash theme={null}
curl -N https://agent.karta.sh/my-org/my-app/v1/chat/completions \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"What roasts do you have?"}],"stream":true}'
```

Each chunk is a bare `data:` line carrying a `chat.completion.chunk` object -
there is no SSE `event:` field. The stream ends with `data: [DONE]`.

```text theme={null}
data: { "id": "chatcmpl_8a1d...", "object": "chat.completion.chunk", "model": "karta", "choices": [ { "index": 0, "delta": { "role": "assistant" }, "finish_reason": null } ] }

data: { "id": "chatcmpl_8a1d...", "object": "chat.completion.chunk", "model": "karta", "choices": [ { "index": 0, "delta": { "content": "We've got " }, "finish_reason": null } ] }

data: { "id": "chatcmpl_8a1d...", "object": "chat.completion.chunk", "model": "karta", "choices": [ { "index": 0, "delta": { "content": "Sunrise, Midnight, ..." }, "finish_reason": null } ] }

data: { "id": "chatcmpl_8a1d...", "object": "chat.completion.chunk", "model": "karta", "choices": [ { "index": 0, "delta": {}, "finish_reason": "stop" } ] }

data: [DONE]
```

## Using the OpenAI SDK

Point an OpenAI client's base URL at your agent and pass the session token as
the API key:

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

client = OpenAI(
    base_url="https://agent.karta.sh/my-org/my-app/v1",
    api_key=session_token,
)
resp = client.chat.completions.create(
    model="karta",
    messages=[{"role": "user", "content": "What roasts do you have?"}],
)
print(resp.choices[0].message.content)
```

## Status codes

`200` (unary or stream), `401`, `402` (budget or instance cap),
`404` (unknown agent / cross-tenant / no active release), `409` (release not
materialized), `422` (malformed body). See [Errors](/api-reference/errors).
