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

# Chat

> Talk to an agent over text — sessions, streaming, and an OpenAI-compatible endpoint.

The same published agent that answers the phone also answers over text. There are two ways to
drive a chat from your backend: the **session API** (durable conversations you create, message,
and end) and an **OpenAI-compatible completions endpoint** (a drop-in for any client that already
speaks the OpenAI chat shape).

## Sessions

A session is a server-side conversation tied to one agent. Create it, post messages, and end it
when done. History is reconstructed for you, so you can fetch the full transcript any time.

Posting a message with `stream: true` returns Server-Sent Events (SSE) — token deltas, tool
calls, and knowledge retrievals arrive as they happen, terminating with an `event: done` (or
`event: error`) frame. With `stream: false` you get the assembled messages in one JSON response.

```bash theme={null}
# Create a session, then send a streaming message
curl -X POST https://builder.flowyte.com/api/v1/chat/sessions \
  -H "Authorization: Bearer flowyte_sk_…" \
  -H "Content-Type: application/json" \
  -d '{"agentId": "AGENT_ID"}'

curl -N -X POST https://builder.flowyte.com/api/v1/chat/sessions/SESSION_ID/messages \
  -H "Authorization: Bearer flowyte_sk_…" \
  -H "Content-Type: application/json" \
  -d '{"content": "Do you deliver to 80202?", "stream": true}'
```

## OpenAI-compatible completions

`POST /chat/completions` accepts the OpenAI request shape — set `model` to the **agent's id**.
Point an existing OpenAI SDK at the base URL `https://builder.flowyte.com/api/v1` and it works
with only a base-URL swap.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://builder.flowyte.com/api/v1/chat/completions \
    -H "Authorization: Bearer flowyte_sk_…" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "AGENT_ID",
      "messages": [{"role": "user", "content": "What are your hours?"}],
      "stream": true
    }'
  ```

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

  client = OpenAI(
      base_url="https://builder.flowyte.com/api/v1",
      api_key="flowyte_sk_…",
  )

  stream = client.chat.completions.create(
      model="AGENT_ID",          # the agent id is the model
      messages=[{"role": "user", "content": "What are your hours?"}],
      stream=True,
  )
  for chunk in stream:
      print(chunk.choices[0].delta.content or "", end="")
  ```

  ```javascript Node theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    baseURL: "https://builder.flowyte.com/api/v1",
    apiKey: "flowyte_sk_…",
  });

  const stream = await client.chat.completions.create({
    model: "AGENT_ID",           // the agent id is the model
    messages: [{ role: "user", content: "What are your hours?" }],
    stream: true,
  });
  for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
  }
  ```
</CodeGroup>

When `stream: true`, this endpoint emits OpenAI-style SSE chunks (`data: {choices:[{delta:…}]}`)
ending with `data: [DONE]`.

## In the API

| Action                             | Endpoint                            | Scope        |
| ---------------------------------- | ----------------------------------- | ------------ |
| Create a session                   | `POST /chat/sessions`               | `chat:write` |
| Get a session                      | `GET /chat/sessions/{id}`           | `chat:read`  |
| List messages                      | `GET /chat/sessions/{id}/messages`  | `chat:read`  |
| Post a message (SSE when `stream`) | `POST /chat/sessions/{id}/messages` | `chat:write` |
| End a session                      | `POST /chat/sessions/{id}/end`      | `chat:write` |
| OpenAI-compatible completion       | `POST /chat/completions`            | `chat:write` |

<Note>
  These endpoints use your **secret key**. To put chat in a browser without exposing a secret, use
  a publishable key and the [Embeddable Widget](/channels/widget).
</Note>
