https://client-api.lala.ist/openapi.json. Fetch it before you generate
code.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 /healthis 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. Growing lists (chat messages, denemeler) page with opaque cursors; date-range reads are bounded by the range instead.
Endpoint table
The SSE contract
POST /api/chat/send responds 200 with text/event-stream.
Lala answers in one message or several. Each message has an index inside the turn.
GET /api/chat/stream responds 200 with text/event-stream and stays open.
error event, with HTTP status
200. Do not map a failed turn to an HTTP status.
Mistakes to avoid
Using EventSource for the stream
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.Sending the conversation history in the request
Sending the conversation history in the request
message and an optional image. The server owns the history.
Sending a message array is not supported and is silently dropped by schema validation.Retrying POST /api/chat/send automatically
Retrying POST /api/chat/send automatically
Sending email, phone, or preferredName to PATCH /api/profile
Sending email, phone, or preferredName to PATCH /api/profile
email and phone; Lala owns preferredName. Schema validation drops
all three. To change an address, run the Supabase auth flow that verifies it. The new value
reaches the profile on the next request.Treating the profile as client-owned state
Treating the profile as client-owned state
GET /api/me instead of
writing back a cached object.Expecting communicationStyle in a response
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.Keying the UI on a message id
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.Assuming one error shape
Assuming one error shape
{"error": string}. Schema validation errors are
{"success": false, "data": ..., "error": [issues]}. Both use status 400 or 401.Treating the plan as client-owned state
Treating the plan as client-owned state
sync
event on the send stream names what changed. Read GET /api/plan again when it says plan,
instead of writing back a cached day.Sending a timestamp for a plan block
Sending a timestamp for a plan block
YYYY-MM-DD) and a wall-clock startTime (HH:MM). There
is no instant, and there is no timezone field. Both fields can be absent: a date with no
startTime is a real block, not an incomplete one.Refusing a plan write on a conflict
Refusing a plan write on a conflict
conflicts and the blocks are still written. Show the overlap. Do not
resend or roll back.Uploading an image as multipart
Uploading an image as multipart
mimeType.Client checklist
Read the token from the Supabase session for each request
Call GET /api/me after sign-in
Register the FCM token with POST /api/devices
Set the chat request timeout to 90 seconds or more
Handle exactly one terminal SSE event, and a dropped socket
Refetch history on foreground, after a push, and after an error
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.jsonor a generated client package. Runnpm 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.