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

# Realtime updates

> GET /api/chat/stream delivers messages the student did not ask for.

`GET /api/chat/stream` is a long-lived `text/event-stream`. It carries everything that reaches the
conversation without a request from this device:

* Scheduled messages that Lala planned earlier.
* The daily check-in after a silence.
* Messages and reactions from the student's other devices.

Open it when the chat screen opens. Keep it open while the application is in the foreground.

```bash theme={null}
curl -N "$BASE_URL/api/chat/stream" \
  -H "Authorization: Bearer $LALA_TOKEN"
```

## Events

<ResponseField name="message" type="StreamMessageEvent">
  A message reached the conversation.

  ```text theme={null}
  event: message
  data: {"message":{"id":"...","role":"lala","content":"nasılsın, 2 gündür haber yok", ...}}
  ```
</ResponseField>

<ResponseField name="reaction" type="StreamReactionEvent">
  The reactions on this message changed. The payload is the whole message.

  ```text theme={null}
  event: reaction
  data: {"message":{"id":"...","reactions":[{"emoji":"🔥","actor":"user", ...}], ...}}
  ```
</ResponseField>

<ResponseField name="ping" type="object">
  A keep-alive, about every 25 seconds. Ignore the payload.

  ```text theme={null}
  event: ping
  data: {}
  ```
</ResponseField>

The `message` payload is a full `ChatMessage`, in the same shape as
[the history](/guides/conversation-history). It needs no extra fetch.

## Rules for the client

1. Merge each `message` into the local list by `id`.
2. The stream repeats messages this device produced through `POST /api/chat/send`. De-duplicate by
   `id`. Do not render the same message twice.
3. On `reaction`, replace the reactions of that message.
4. If no `ping` arrives for 60 seconds, treat the stream as dead and reconnect.
5. After a reconnect, read `GET /api/chat/messages?after=<cursor of your newest message>` to fill
   the gap.

<Warning>
  Do not use the browser `EventSource` API. `EventSource` cannot set the `Authorization` header. Use
  `fetch` with a stream reader.
</Warning>

## Push and the stream

Push notifications and this stream cover different states. Push reaches a closed application. The
stream reaches an open one. The server does both for every proactive message, so an open
application can receive a push it does not need. Read
[Push notifications](/guides/push-notifications).

## Delivery

The stream is best effort. A message always reaches the database first, and the stream announces
it after. A dropped event costs you the live update, not the message. The `after` parameter
recovers it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.