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

# Notes for AI agents

> A dense, unambiguous fact sheet for a coding agent that integrates the Lala API.

This page is written for an agent that writes client code. Every fact here is also somewhere else
on this site. Nothing here contradicts the OpenAPI document. When they disagree, the OpenAPI
document wins.

<Note>
  Machine-readable spec: `https://client-api.lala.ist/openapi.json`. Fetch it before you generate
  code.
</Note>

## Hard facts

* Base URL, production: `https://client-api.lala.ist`
* Base URL, local: `http://localhost:3000`
* Auth: `Authorization: Bearer <supabase_access_token>`. No API key exists.
* Only `GET /health` is unauthenticated.
* Content type for requests with a body: `application/json`.
* Timestamps are UTC, ISO 8601. Lala's own day runs on `Europe/Istanbul`.
* All student-visible text is Turkish. All identifiers and error strings are English.
* There is no rate limit today. There is no pagination anywhere.

## Endpoint table

| Method  | Path                | Request            | Success                       |
| ------- | ------------------- | ------------------ | ----------------------------- |
| `GET`   | `/health`           | —                  | `{"ok":true}`                 |
| `GET`   | `/api/me`           | —                  | `MeResponse`                  |
| `PATCH` | `/api/profile`      | `ProfilePatchBody` | `{"profile": StudentProfile}` |
| `POST`  | `/api/chat/send`    | `ChatSendBody`     | `text/event-stream`           |
| `GET`   | `/api/chat/history` | —                  | `{"messages": ChatMessage[]}` |

## The SSE contract

`POST /api/chat/send` responds `200` with `text/event-stream`.

| Event   | Data                                                 | Repeats | Terminal |
| ------- | ---------------------------------------------------- | ------- | -------- |
| `chunk` | `{"text": string}`                                   | yes     | no       |
| `done`  | `{"text": string, "reactions": [{"emoji": string}]}` | no      | yes      |
| `error` | `{"error": string}`                                  | no      | yes      |

Exactly one terminal event per stream. A model failure is an `error` event, with HTTP status
`200`. Do not map a failed turn to an HTTP status.

## Mistakes to avoid

<AccordionGroup>
  <Accordion title="Using EventSource for the stream">
    `EventSource` sends `GET` and cannot set the `Authorization` header. Use `fetch`, or an HTTP
    client that exposes the response body as a byte stream, and parse the SSE lines yourself.
  </Accordion>

  <Accordion title="Sending the conversation history in the request">
    The request body holds only `message` and an optional `image`. The server owns the history.
    Sending a message array is not supported and is silently dropped by schema validation.
  </Accordion>

  <Accordion title="Retrying POST /api/chat/send automatically">
    The student message is persisted before the model runs. An automatic retry duplicates it.
    Retry only on an explicit student action.
  </Accordion>

  <Accordion title="Treating the profile as client-owned state">
    Lala updates the profile itself during a conversation. Re-read `GET /api/me` instead of
    writing back a cached object.
  </Accordion>

  <Accordion title="Expecting communicationStyle in a response">
    `PATCH /api/profile` accepts `communicationStyle`, but no response returns it. It is stored
    with the conversation context, not the profile.
  </Accordion>

  <Accordion title="Keying the UI on a message id">
    `ChatMessage.id` is optional and is not present on every message. Rebuild the list from the
    server response instead.
  </Accordion>

  <Accordion title="Assuming one error shape">
    Route errors are `{"error": string}`. Schema validation errors are
    `{"success": false, "data": ..., "error": [issues]}`. Both use status `400` or `401`.
  </Accordion>

  <Accordion title="Uploading an image as multipart">
    There is no upload endpoint. The image goes inline as base64 in the chat body, with a
    `mimeType`.
  </Accordion>
</AccordionGroup>

## Client checklist

<Steps>
  <Step title="Read the token from the Supabase session for each request">
    Do not cache the string. The library refreshes it.
  </Step>

  <Step title="Call GET /api/me after sign-in">
    It creates the student row and tells you whether onboarding is complete.
  </Step>

  <Step title="Set the OneSignal external_id to the same id">
    Without the alias, proactive messages never reach the device.
  </Step>

  <Step title="Set the chat request timeout to 90 seconds or more">
    The server aborts the model after 60 seconds, and a turn can run several tool steps.
  </Step>

  <Step title="Handle exactly one terminal SSE event, and a dropped socket">
    A dropped socket with no terminal event is a failed turn on the client. The server still
    finishes it.
  </Step>

  <Step title="Refetch history on foreground, after a push, and after an error">
    The history endpoint is the source of truth.
  </Step>
</Steps>

## Do not generate

* Do not generate a stream reader from the OpenAPI document. The SSE framing is not in it.
* Do not hand-edit `openapi.json` or a generated client package. Run `npm run openapi:emit`.
* Do not invent endpoints. Version 1 has the five routes in the table above, and nothing else.
* Do not translate or rewrite Turkish text from the API. Render it as it arrives.
