> ## 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.

# Messages

> Send a turn into a session - accumulated JSON, or a streamed sequence of typed SSE events.

Send a message to a session and get the agent's turn back. Set `stream` to
choose the response shape.

`POST /v1/sessions/{session_id}/messages` -
`POST /{org}/{agent}/v1/sessions/{session_id}/messages`

## Request

<ParamField body="text" type="string" required>
  The message to send.
</ParamField>

<ParamField body="agent" type="string">
  Route this turn to a named [sub-agent](/concepts/agents). Defaults to the
  session's current sub-agent.
</ParamField>

<ParamField body="participant_name" type="string">
  The sending [participant](/concepts/sessions-and-participants); messages are
  attributed to it.
</ParamField>

<ParamField body="participant_type" type="string">
  `human` or `ai`.
</ParamField>

<ParamField body="thinking" type="boolean" default="false">
  Surface extended-thinking / `reasoning` events.
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  `true` -> Server-Sent Events. `false` -> a single accumulated JSON response.
</ParamField>

## Unary response (`stream: false`)

```bash theme={null}
curl https://api.karta.sh/v1/sessions/$SID/messages \
  -H "Authorization: Bearer $KARTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "What roasts do you have?"}'
```

```json theme={null}
{
  "text": "We've got Sunrise, Midnight, and Decaf Dusk. ",
  "session_id": "sess_9f3a...",
  "agent": "default",
  "messages": [
    { "id": "msg_1", "role": "user",      "text": "What roasts do you have?", "parts": [/* ... */] },
    { "id": "msg_2", "role": "assistant", "text": "We've got Sunrise, ...",      "parts": [/* ... */] }
  ],
  "usage": { "input_tokens": 42, "output_tokens": 28, "total_tokens": 70 }
}
```

## Streaming response (`stream: true`)

```bash theme={null}
curl -N https://api.karta.sh/v1/sessions/$SID/messages \
  -H "Authorization: Bearer $KARTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "What roasts do you have?", "stream": true}'
```

```text theme={null}
event: text
data: {"type":"text","session_id":"sess_9f3a...","data":{"part":{"type":"text","text":"We've got "}}}

event: text
data: {"type":"text","session_id":"sess_9f3a...","data":{"part":{"type":"text","text":"Sunrise, Midnight, ..."}}}

event: done
data: {"type":"done","data":{"usage":{"input_tokens":42,"output_tokens":28,"total_tokens":70}}}
```

The stream is the [typed event model](/concepts/streaming-events): `text`,
`tool_use`, `reasoning`, `step_start`, `step_finish`, `input_required`,
`error`, `done`. A turn may pause with `input_required` to request approval -
resolve it via [Inputs](/api-reference/inputs).

## Status codes

| Status | When                                                                                 |
| ------ | ------------------------------------------------------------------------------------ |
| `200`  | Success (unary or stream start).                                                     |
| `401`  | Missing/invalid credential.                                                          |
| `402`  | Budget exhausted - returned before the turn runs.                                    |
| `403`  | A metadata end-user id that conflicts with the verified token (`identity_mismatch`). |
| `404`  | Session not found, another org's, or the agent has no active release.                |
| `409`  | Agent route: a release exists but is not materialized.                               |
| `422`  | BYOK key rejected (unary). In streaming, this is an `error` event.                   |

<Note>
  Want to drive an agent with an existing OpenAI or Anthropic client instead of
  this native shape? Use a [consumer adapter](/api-reference/adapters/overview)

  * same turn, re-framed into those wire formats.
</Note>
