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

# Change a block

> Partial update. The server writes only the fields in the body.

Timing merges onto what is stored: send `startTime` alone to move the block and keep
its length, `startTime: null` to take the time off and keep the length, `date` alone to
move it to another day.

Set `status` to `done` to tick the block off — the server stamps `completedAt`. Send
`doneQuestions` with it when you know the count.



## OpenAPI

````yaml /api-reference/openapi.json patch /api/plan/{id}
openapi: 3.1.0
info:
  title: Lala Client API
  description: >-
    The HTTP API behind Lala, the AI study companion for Turkish YKS and LGS
    students. This document is generated from the Zod schemas that validate each
    request at runtime. Do not hand-edit openapi.json. Student-visible text is
    Turkish. All identifiers are English.
  version: 1.0.0
servers:
  - url: https://client-api.lala.ist
    description: production
  - url: http://localhost:3000
    description: local dev
security:
  - supabaseJwt: []
tags:
  - name: chat
    description: The chat stream, the message history, and reactions
  - name: media
    description: Upload and read message attachments
  - name: plan
    description: The study planner — blocks of work on a day
  - name: journey
    description: Deneme results, topic performance, study-hours stats, and the streak
  - name: profile
    description: The student profile and onboarding
  - name: devices
    description: Push notification devices
  - name: system
    description: Health check
paths:
  /api/plan/{id}:
    patch:
      tags:
        - plan
      summary: Change a block
      description: >-
        Partial update. The server writes only the fields in the body.


        Timing merges onto what is stored: send `startTime` alone to move the
        block and keep

        its length, `startTime: null` to take the time off and keep the length,
        `date` alone to

        move it to another day.


        Set `status` to `done` to tick the block off — the server stamps
        `completedAt`. Send

        `doneQuestions` with it when you know the count.
      operationId: patchApiPlanById
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanBlockPatchBody'
      responses:
        '200':
          description: The block after the change, and any overlaps
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanWriteResponse'
        '400':
          description: The block or the range is not valid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: The token is missing, expired, or invalid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: No such block for this student
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    PlanBlockPatchBody:
      type: object
      properties:
        date:
          description: Local Istanbul calendar date, `YYYY-MM-DD`. Moves the block.
          type: string
        startTime:
          description: >-
            Local Istanbul wall clock, `HH:MM`. Leave it out for a block with no
            time yet.
          anyOf:
            - type: string
            - type: 'null'
        endTime:
          description: >-
            Optional, and it needs a `startTime`. It sets the length, and it
            wins over `durationMin`. An end before the start is a block that
            runs past midnight.
          anyOf:
            - type: string
            - type: 'null'
        durationMin:
          description: >-
            The length in minutes. Valid on its own: "45 minutes, time
            undecided".
          anyOf:
            - type: integer
              minimum: 5
              maximum: 720
            - type: 'null'
        subject:
          type: string
          minLength: 1
          maxLength: 64
        topic:
          anyOf:
            - type: string
              maxLength: 200
            - type: 'null'
        activity:
          type: string
          maxLength: 40
        targetQuestions:
          anyOf:
            - type: integer
              minimum: 1
              maximum: 2000
            - type: 'null'
        notes:
          anyOf:
            - type: string
              maxLength: 1000
            - type: 'null'
        position:
          type: integer
          minimum: 0
          maximum: 1000
        status:
          $ref: '#/components/schemas/PlanStatus'
        doneQuestions:
          anyOf:
            - type: integer
              minimum: 0
              maximum: 2000
            - type: 'null'
      description: >-
        Partial update. Only the fields present are written. `startTime: null`
        takes the time off the block and keeps its length. `completedAt` follows
        `status` and is not accepted.
    PlanWriteResponse:
      type: object
      properties:
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/PlanBlock'
        conflicts:
          type: array
          items:
            $ref: '#/components/schemas/PlanConflict'
      required:
        - blocks
        - conflicts
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        issues:
          description: >-
            Present only on a 400 raised by request validation, capped at 10
            entries. Every other error carries `error` alone.
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssue'
      required:
        - error
      description: Error body. `error` is a short English string.
    PlanStatus:
      type: string
      enum:
        - planned
        - done
        - skipped
    PlanBlock:
      type: object
      properties:
        id:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
        date:
          type: string
          description: Local Istanbul calendar date, `YYYY-MM-DD`.
        startTime:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Local Istanbul wall clock, `HH:MM`. Null while the time is
            undecided.
        endTime:
          anyOf:
            - type: string
            - type: 'null'
          description: Derived from the start and the length. Null unless both are known.
        durationMin:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
        scheduled:
          type: boolean
          description: True when the block has a time, not only a date.
        subject:
          type: string
        topic:
          anyOf:
            - type: string
            - type: 'null'
          description: Free text. `türev`, `paragraf`, …
        activity:
          $ref: '#/components/schemas/PlanActivity'
        targetQuestions:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
        notes:
          anyOf:
            - type: string
            - type: 'null'
        status:
          $ref: '#/components/schemas/PlanStatus'
        doneQuestions:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
        completedAt:
          anyOf:
            - type: string
              format: date-time
              pattern: >-
                ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
            - type: 'null'
          description: Server-set when the status becomes `done`. Read-only.
        createdBy:
          type: string
          enum:
            - student
            - lala
          description: Who added the block. `lala` when it came out of a chat.
        position:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
          description: Manual order among the blocks of a day that have no time.
        createdAt:
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
        updatedAt:
          type: string
          format: date-time
          pattern: >-
            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
      required:
        - id
        - date
        - startTime
        - endTime
        - durationMin
        - scheduled
        - subject
        - topic
        - activity
        - targetQuestions
        - notes
        - status
        - doneQuestions
        - completedAt
        - createdBy
        - position
        - createdAt
        - updatedAt
    PlanConflict:
      type: object
      properties:
        blockId:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
        conflictsWith:
          type: array
          items:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
      required:
        - blockId
        - conflictsWith
      description: >-
        Blocks that overlap in time. A write is never refused for an overlap —
        the student may mean it. Show it, do not block it.
    ValidationIssue:
      type: object
      properties:
        path:
          type: string
          description: Dotted path to the offending field, empty at the root.
        message:
          type: string
      required:
        - path
        - message
    PlanActivity:
      type: string
      enum:
        - questions
        - lesson
        - review
        - subject_mock
        - mock_exam
        - homework
        - reading
        - break
        - other
      description: >-
        What the block is. Turkish labels, in order: soru çözümü, konu anlatımı,
        tekrar, branş denemesi, deneme, ödev, okuma, mola, çalışma. On write,
        the Turkish name is accepted too (`soru çözümü`, `branş denemesi`, …).
  securitySchemes:
    supabaseJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Supabase access token: `Authorization: Bearer <token>`'

````

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