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

# Consume Session Events (SSE)

> Subscribe to a lens session’s Server-Sent Events stream to receive asynchronous inference results

## Overview

This endpoint opens a [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) stream for an active lens session. Output processors of type `server_sent_events_writer` (used by the Activity Monitor lens and most cookbook lenses) write inference results, log messages, and stream status events to this channel.

<Note>
  Lens sessions route outputs through **one of two channels**, never both:

  * **SSE consumer** (this endpoint) — for lenses whose `model_pipeline` includes a `server_sent_events_writer` output processor.
  * **WebSocket mailbox** — drained via [`session.read`](/api-reference/lens/websocket-events#session-read).

  If [`session.read`](/api-reference/lens/websocket-events#session-read) returns `event_data: null` while [`GET /lens/sessions/metadata`](/api-reference/lens/get-sessions-metadata) shows non-zero `num_outputs`, the lens is writing to the SSE consumer — use this endpoint.

  The official [`archetypeai` Python SDK](https://pypi.org/project/archetypeai/) exposes this endpoint as `lens.create_sse_consumer(session_id)`.
</Note>

## Path Parameters

<ParamField path="session_id" type="string" required>
  Identifier of the active session whose output stream to subscribe to. Returned by [Create Lens Session](/api-reference/lens/create-session).
</ParamField>

## Headers

<ParamField header="Authorization" type="string" required>
  `Bearer YOUR_API_KEY`
</ParamField>

<ParamField header="Accept" type="string">
  `text/event-stream` (recommended — signals SSE intent to the server and to intermediaries)
</ParamField>

<ParamField header="Last-Event-ID" type="string">
  Optional cursor. When set, the server resumes the stream after the event with the given `id`, so reconnecting clients do not miss or duplicate messages. Matches the standard SSE reconnection semantic.
</ParamField>

## Response

The response is an `text/event-stream` HTTP response. Each frame is a standard SSE record:

```
event: message
id: <opaque cursor>
data: {"type": "<event.type>", ...}

```

The `data:` payload is JSON and always includes a `type` field identifying the event. The consumer emits three envelope event types in addition to lens-specific output events:

<ResponseField name="type=sse.stream.start" type="event">
  First frame emitted after the connection is established. Carries the `session_id` of the stream and a server-assigned `reader_id` that identifies this consumer connection.

  ```json theme={"system"}
  {
    "type": "sse.stream.start",
    "event_data": {
      "session_id": "lsn-...",
      "reader_id": "<opaque>"
    }
  }
  ```
</ResponseField>

<ResponseField name="type=sse.stream.heartbeat" type="event">
  Periodic keepalive frame used to hold the connection open through proxies and to surface session-side counters. `message_timeout` increments with each heartbeat — clients should ignore the payload contents but can use the frame as a liveness signal.

  ```json theme={"system"}
  {
    "type": "sse.stream.heartbeat",
    "event_data": {
      "session_id": "lsn-...",
      "session_status": "SESSION_STATUS_RUNNING",
      "num_messages": 0,
      "num_bytes": 0,
      "message_timeout": 5.0
    }
  }
  ```
</ResponseField>

<ResponseField name="type=sse.stream.end" type="event">
  The server is closing the stream gracefully (for example, the session was destroyed). Clients should stop consuming after receiving this event.
</ResponseField>

All other `type` values are lens-specific output events. Typical types emitted by `server_sent_events_writer` include `inference.result`, `log.info`, `frame.processed`, and `error`. The exact shape of the `data` payload depends on the lens's `model_pipeline` and the processor that produced the event.

<RequestExample>
  ```bash cURL theme={"system"}
  curl -N https://api.u1.archetypeai.app/v0.5/lens/sessions/consumer/lsn-250313c2177253cbaa7a73542edd90 \
    -H "Authorization: Bearer $ATAI_API_KEY" \
    -H "Accept: text/event-stream"
  ```

  ```python Python theme={"system"}
  import json
  import requests
  import os

  api_key = os.environ.get("ATAI_API_KEY")
  session_id = "lsn-250313c2177253cbaa7a73542edd90"

  with requests.get(
      f"https://api.u1.archetypeai.app/v0.5/lens/sessions/consumer/{session_id}",
      headers={
          "Authorization": f"Bearer {api_key}",
          "Accept": "text/event-stream",
      },
      stream=True,
      timeout=(10, None),
  ) as resp:
      resp.raise_for_status()
      for line in resp.iter_lines(decode_unicode=True):
          if not line or not line.startswith("data:"):
              continue
          payload = json.loads(line[len("data:"):].strip())
          if payload.get("type") == "sse.stream.heartbeat":
              continue
          if payload.get("type") == "sse.stream.end":
              break
          print(payload)
  ```

  ```python Python (SDK) theme={"system"}
  from archetypeai import ArchetypeAI

  client = ArchetypeAI()
  reader = client.lens.create_sse_consumer(session_id="lsn-250313c2177253cbaa7a73542edd90")
  for event in reader.read(block=True):
      print(event)
  ```

  ```javascript JavaScript theme={"system"}
  // EventSource cannot set Authorization headers; use fetch with a streaming
  // reader instead.
  const sessionId = "lsn-250313c2177253cbaa7a73542edd90";

  const response = await fetch(
    `https://api.u1.archetypeai.app/v0.5/lens/sessions/consumer/${sessionId}`,
    {
      headers: {
        Authorization: `Bearer ${process.env.ATAI_API_KEY}`,
        Accept: "text/event-stream",
      },
    }
  );

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });

    let idx;
    while ((idx = buffer.indexOf("\n\n")) !== -1) {
      const frame = buffer.slice(0, idx);
      buffer = buffer.slice(idx + 2);

      const dataLine = frame.split("\n").find((l) => l.startsWith("data:"));
      if (!dataLine) continue;
      const payload = JSON.parse(dataLine.slice("data:".length).trim());
      if (payload.type === "sse.stream.heartbeat") continue;
      if (payload.type === "sse.stream.end") return;
      console.log(payload);
    }
  }
  ```
</RequestExample>

<ResponseExample>
  ```text 200 - Success (excerpt) theme={"system"}
  event: message
  data: {"type": "sse.stream.start", "event_data": {"session_id": "lsn-...", "reader_id": "87e6d51c992557bc"}}

  event: message
  data: {"type": "sse.stream.heartbeat", "event_data": {"session_id": "lsn-...", "session_status": "SESSION_STATUS_RUNNING", "num_messages": 0, "num_bytes": 0, "message_timeout": 5.0}}

  event: message
  data: {"type": "inference.result", "timestamp": 1741843200.123, "data": {"result": "A construction worker wearing a hard hat and safety vest"}}

  event: message
  data: {"type": "sse.stream.end"}
  ```

  ```json 401 - Unauthorized theme={"system"}
  {
    "errors": [
      {
        "code": "unauthorized_request",
        "message": "Unauthorized or invalid access.",
        "suggestion": "Provide valid authentication credentials and ensure they have the required permissions.",
        "error_uid": "err-xxxxxxxx"
      }
    ]
  }
  ```

  ```json 404 - Session not found theme={"system"}
  {
    "errors": [
      {
        "code": "session_not_found",
        "message": "No session with the given session_id was found for the organization.",
        "suggestion": "Verify the session_id and that the session has not been destroyed.",
        "error_uid": "err-xxxxxxxx"
      }
    ]
  }
  ```
</ResponseExample>

## Choosing Between SSE and `session.read`

|                     | SSE consumer (this endpoint)                              | [`session.read`](/api-reference/lens/websocket-events#session-read) |
| ------------------- | --------------------------------------------------------- | ------------------------------------------------------------------- |
| **Transport**       | HTTP `text/event-stream`                                  | WebSocket event over `session_endpoint`                             |
| **Pattern**         | Server pushes events as they arrive                       | Client polls; server returns queued messages                        |
| **Used by**         | Lenses with `server_sent_events_writer` output processors | Lenses with mailbox-style output processors                         |
| **Cursor / resume** | `Last-Event-ID` request header                            | `client_id` field in `event_data`                                   |
| **Heartbeats**      | `sse.stream.heartbeat` envelope events                    | None (request/response pattern)                                     |
| **Graceful close**  | `sse.stream.end` envelope event, then HTTP close          | Close WebSocket                                                     |

Inspect the lens's `model_pipeline` via [`GET /lens/metadata`](/api-reference/lens/get-metadata) to see which output processor (and therefore which channel) it uses.
