# Sessions: group requests into a conversation

> Keep a conversation's requests together with the opencheese-session-uuid header: when to send it, its format, and examples in curl, Python and JavaScript.
>
> Web page: https://opencheese.dev/en/docs/sessions/ · Every docs page: https://opencheese.dev/llms.txt

A session is one conversation: every request that belongs to it, grouped under one row in the
dashboard's **Transactions**, with the conversation's total tokens and cost. Sessions also let
context compaction (the **Context Compacter** page) keep a long conversation within the
model's context window.

## Supported tools group by themselves

OpenCode, Claude Code, Claude Desktop, Codex, Harness AI, Zed, RikkaHub and LobeHub (through
its New API entry) already group their requests: one conversation in the tool is one session in
the dashboard, with nothing to configure. Chatbox requests appear as separate sessions for now.

Everything else, such as your own scripts and SDK calls, starts a new session with every request
unless it names one.

## Name the session with a header

Send the same `opencheese-session-uuid` header with every request of the conversation:

```bash
SESSION=$(uuidgen)

curl https://api.opencheese.dev/v1/chat/completions \
  -H "Authorization: Bearer $OPENCHEESE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "opencheese-session-uuid: $SESSION" \
  -d '{"model": "MODEL_ID", "messages": [{"role": "user", "content": "Name three cheeses."}]}'
```

The header works the same way on `/v1/chat/completions`, `/v1/responses`, `/v1/messages` and
the image endpoints, so a conversation that mixes them stays one session.

## When to send it

Send one session id per conversation when:

- a chat or agent loop sends several requests that build on each other;
- your app makes background calls for a conversation, such as a title or a summary: give them
  the conversation's id so their cost is counted with it;
- one task spans several models: the session keeps them together.

Leave the header out when the requests are independent, such as a batch of classifications or
a one-off question. Each request is then its own session.

Never reuse one id for unrelated conversations: they would appear as one session, and context
compaction would treat them as one conversation.

## Format

- Use a new random UUID (version 4) for each conversation, such as
  `2f1c6d0e-8a4b-4c55-9b7e-3d2a1f0e9c84`.
- The gateway also accepts any id of 1 to 256 characters made of letters, digits, `_`, `.`,
  `:` and `-`, but a UUID is the safe choice.
- Any other value is refused with `invalid_session_header` (HTTP 400; on
  `/v1/chat/completions` it arrives as the assistant's reply).

Every chat, responses, messages and image response returns the session id it was recorded
under in the `opencheese-session-uuid` response header, streaming responses included. Without
your own header that is a new id, which you can send back on the next request to continue the
same session.

## Python

```python
import uuid
from openai import OpenAI

client = OpenAI(base_url="https://api.opencheese.dev/v1", api_key="YOUR_OPENCHEESE_API_KEY")
session = str(uuid.uuid4())
history = [{"role": "user", "content": "Name three cheeses."}]

first = client.chat.completions.create(
    model="MODEL_ID",
    messages=history,
    extra_headers={"opencheese-session-uuid": session},
)
history.append({"role": "assistant", "content": first.choices[0].message.content})
history.append({"role": "user", "content": "Which one melts best?"})

second = client.chat.completions.create(
    model="MODEL_ID",
    messages=history,
    extra_headers={"opencheese-session-uuid": session},
)
print(second.choices[0].message.content)
```

With the Anthropic SDK, pass the same header as `extra_headers` to `client.messages.create`, or
once for the whole client as `default_headers`.

## JavaScript

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.opencheese.dev/v1",
  apiKey: process.env.OPENCHEESE_API_KEY,
  defaultHeaders: { "opencheese-session-uuid": crypto.randomUUID() }
});

const reply = await client.chat.completions.create({
  model: "MODEL_ID",
  messages: [{ role: "user", content: "Name three cheeses." }]
});
console.log(reply.choices[0].message.content);
```

A client created with `defaultHeaders` puts all of its requests in one session, so create one
client per conversation, or pass the header per request with
`client.chat.completions.create(body, { headers: { "opencheese-session-uuid": id } })`.
