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

# SSE Event Stream

Qoder Cloud Agents streams public Session events over **Server-Sent Events (SSE)**.

## Connection URL

```text theme={null}
GET https://api.qoder.com/api/v1/cloud/sessions/{session_id}/events/stream
```

Request headers:

```text theme={null}
Authorization: Bearer $QODER_PAT
Accept: text/event-stream
```

By default, an Agent response is written to the Session event history and emitted on the stream as a complete public event, such as `agent.message`, after generation finishes. This guide calls that complete event a **buffered event**.

The stream endpoint supports the `Last-Event-ID` header for reconnection. For ordinary buffered events, the stream resumes after that ID. In-progress event deltas have the additional behavior described below.

Use `event_deltas[]` to receive an Agent response incrementally on this stream connection. Repeat the parameter to request both supported event types:

```text theme={null}
GET /api/v1/cloud/sessions/{session_id}/events/stream?event_deltas[]=agent.message
GET /api/v1/cloud/sessions/{session_id}/events/stream?event_deltas[]=agent.thinking
GET /api/v1/cloud/sessions/{session_id}/events/stream?event_deltas[]=agent.message&event_deltas[]=agent.thinking
```

The selection applies only to the current stream connection and does not affect other connections to the same Session. Without `event_deltas[]`, the connection receives only the complete event after the response finishes. Thread event streams do not support this parameter.

## SSE Format

Each event uses standard SSE fields:

```text theme={null}
id: evt_019e392c0d787cfaa21bda98e06cd913
event: agent.message
data: {"id":"evt_019e392c0d787cfaa21bda98e06cd913","type":"agent.message","content":[{"type":"text","text":"Hello"}],"processed_at":"2026-05-18T03:40:48.888851795Z"}
```

Heartbeat comments may be sent to keep the connection alive.

## Event Deltas

Incremental `agent.message` output begins with `event_start`, followed by one or more `event_delta` frames:

```text theme={null}
id: evt_00jjujk9fbnr4wkj2gh8
event: event_start
data: {"event":{"id":"evt_00jjujk9fbnr4wkj2gh8","type":"agent.message"},"type":"event_start"}

id: evt_00jjujk9fbnr4wkj2gh8
event: event_delta
data: {"delta":{"content":{"text":"Hello","type":"text"},"index":0,"type":"content_delta"},"event_id":"evt_00jjujk9fbnr4wkj2gh8","type":"event_delta"}
```

Incremental `agent.thinking` output is start-only. No `event_delta` frames follow:

```text theme={null}
id: evt_00jjujk9fbnr55q5rtyp
event: event_start
data: {"event":{"id":"evt_00jjujk9fbnr55q5rtyp","type":"agent.thinking"},"type":"event_start"}
```

The SSE `id:`, `event_start.event.id`, every `event_delta.event_id`, and the later buffered event `id` are identical for the same message or thinking event. A typical response with both event types follows this order:

```text theme={null}
span.model_request_start
event_start (agent.thinking)
agent.thinking
event_start (agent.message)
event_delta (agent.message)
agent.message
span.model_request_end
```

Event delta frames do not contain top-level JSON `id` or `processed_at` fields. They do not appear in event list/history responses. The buffered `agent.message` is the authoritative result, and `agent.thinking` never exposes reasoning content.

## Reconnecting During Event Deltas

Use the SSE `Last-Event-ID` header when reconnecting. Behavior depends on the cursor and whether the message is still being generated:

1. **The cursor is an event before the current `event_start`, and generation is still in progress.** The stream replays that message's `event_start` and retained historical `event_delta` frames, then continues with new deltas.
2. **The cursor equals the current `event_start.event.id`, and generation is still in progress.** Historical deltas for that message are not replayed. The stream emits only deltas generated after reconnection, followed by the buffered final event.
3. **Generation has completed.** Historical deltas for that message are no longer replayed. Reconnecting from an earlier buffered event yields the final `agent.message`; reconnecting with that final message's ID resumes after it.

All frames for one incrementally streamed event use the same ID. If a client needs to rebuild the entire in-progress event after a disconnect, it should reconnect using the buffered event ID immediately before that event's `event_start`, discard or deduplicate its partial local state, and process the replayed `event_start` and `event_delta` frames again.

## Common Event Flow

```text theme={null}
session.status_running
session.thread_status_running
user.message
span.model_request_start
agent.thinking
agent.tool_use
agent.tool_result
agent.message
span.model_request_end
session.thread_status_idle
session.status_idle
```

Not every turn contains every event. Managed-agent Sessions can also emit thread events such as `session.thread_created`, `session.thread_status_running`, `agent.thread_message_sent`, and `agent.thread_message_received`.

### Model request spans

`span.model_request_start` contains `id`, `processed_at`, and `type`. The matching `span.model_request_end` contains `id`, `is_error`, `model_request_start_id`, `processed_at`, and `type`. Its `model_request_start_id` equals the corresponding start event's `id`.

> Note: Public `agent.thinking` events only carry `id`, `processed_at`, and `type`. The reasoning content is intentionally not exposed; treat the event as a marker that the Agent paused to reason. Several other agent-generated events also omit `processed_at` — treat the field as optional when parsing.

## Connection lifecycle

* `session.status_idle` indicates the current turn finished. The connection should stay open and wait for the next turn.
* `session.status_terminated` and `session.deleted` are terminal — the client should stop reconnecting; further events will not arrive.
* `session.status_rescheduled` is a transient signal; the stream may briefly disconnect, then reconnect once the runtime is ready.
* For network drops, reconnect with the `Last-Event-ID` header. See [Reconnecting During Event Deltas](#reconnecting-during-event-deltas) for the special handling of an in-progress event.

## Tool Responses

When the stream emits an `agent.tool_use` that requires confirmation, send `user.tool_confirmation` to `POST /api/v1/cloud/sessions/{session_id}/events` with the tool event ID:

```json theme={null}
{
  "events": [
    {
      "type": "user.tool_confirmation",
      "tool_use_id": "evt_01JZ6Q3FB6SG8F7J1M2N",
      "result": "allow"
    }
  ]
}
```

When the stream emits `agent.custom_tool_use`, execute the custom tool in your client and send `user.custom_tool_result`.

## Event History

Use the list endpoint for historical events and pagination:

```bash theme={null}
curl -s "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/events?limit=20&order=desc" \
  -H "Authorization: Bearer $QODER_PAT"
```

List responses use `data` and `next_page`. See [List events](/cloud-agents/api/sessions/list-events) and [Session schemas](/cloud-agents/api/sessions/schemas#public-event-types).
