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

# Update Appointment

> Update an appointment you own by its ID

## Overview

Updates an existing appointment. Access is owner-only: the appointment's
`doctor_id` must match the caller, otherwise a `403 Forbidden` is returned.
Ownership cannot be changed — any `doctor_id` sent in the body is ignored.

<Note>
  Most fields use a fallback assignment (`value || existing`), so sending an
  empty or falsy value does **not** overwrite the current value — for example
  `notes` cannot be cleared with `""`. Only `room`, `error_reason` and
  `doctor_note` can be explicitly cleared.
</Note>

## Authentication

<ParamField header="Authorization" type="string" required>
  Bearer token for authenticated access.

  ```
  Authorization: Bearer <JWT>
  ```
</ParamField>

## Path Parameters

<ParamField path="id" type="string" required>
  Appointment ObjectId to update. Owner-only.
</ParamField>

## Body Parameters

<ParamField body="name" type="string">
  New title. A falsy value is ignored.
</ParamField>

<ParamField body="date" type="string">
  New date. Blocked with `409` on externally-synced appointments.
</ParamField>

<ParamField body="time" type="string">
  New time. Blocked with `409` on externally-synced appointments.
</ParamField>

<ParamField body="duration_minutes" type="number">
  Duration in minutes, `5`–`480`; otherwise `400`. Blocked with `409` on
  externally-synced appointments.
</ParamField>

<ParamField body="status" type="string">
  Recording lifecycle status. Status transitions are timestamped internally.
</ParamField>

<ParamField body="error_reason" type="string">
  Failure reason. Unlike most fields, this can be explicitly cleared to `null`
  or an empty string.
</ParamField>

<ParamField body="recording_id" type="string">
  Recording id. A falsy value is ignored.
</ParamField>

<ParamField body="recording_url" type="string">
  Recording URL. A falsy value is ignored.
</ParamField>

<ParamField body="recording_key" type="string">
  Recording storage key. A falsy value is ignored.
</ParamField>

<ParamField body="notes" type="string">
  Private clinical notes. A falsy value is ignored (cannot be cleared with `""`).
</ParamField>

<ParamField body="language" type="string">
  Language code. A falsy value is ignored.
</ParamField>

<ParamField body="notes_type" type="string">
  Notes template key. A falsy value is ignored.
</ParamField>

<ParamField body="appointment_type" type="string">
  Appointment type. A falsy value is ignored.
</ParamField>

<ParamField body="room" type="string">
  Room / location label. An empty string clears it to `null`. Independent of the
  external-readonly guard.
</ParamField>

<ParamField body="doctor_note" type="string">
  Patient-facing note. Only applied when the appointment already has a booking.
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  Whether the request succeeded.
</ResponseField>

<ResponseField name="data" type="object">
  The updated appointment object (same shape as
  [Get Appointment](/api-reference/appointments/get)).

  <Expandable title="Appointment Object">
    <ResponseField name="_id" type="string">
      Unique appointment identifier (ObjectId).
    </ResponseField>

    <ResponseField name="name" type="string">
      Appointment title.
    </ResponseField>

    <ResponseField name="date" type="string">
      Appointment date, serialized as a full ISO datetime.
    </ResponseField>

    <ResponseField name="time" type="string">
      Wall-clock time, `HH:mm`.
    </ResponseField>

    <ResponseField name="status" type="string">
      Recording lifecycle status.
    </ResponseField>

    <ResponseField name="error_reason" type="string | null">
      Human-readable failure reason, or `null`.
    </ResponseField>

    <ResponseField name="doctor_id" type="string">
      Owning doctor's user id.
    </ResponseField>

    <ResponseField name="notes" type="string">
      Private clinical notes.
    </ResponseField>

    <ResponseField name="language" type="string">
      Language code.
    </ResponseField>

    <ResponseField name="notes_type" type="string | null">
      Notes template key.
    </ResponseField>

    <ResponseField name="appointment_type" type="string">
      Free-form appointment type.
    </ResponseField>

    <ResponseField name="room" type="string | null">
      Room / location label, or `null`.
    </ResponseField>

    <ResponseField name="duration_minutes" type="number | null">
      Duration in minutes, or `null`.
    </ResponseField>

    <ResponseField name="deletionDate" type="string">
      ISO datetime for automatic deletion.
    </ResponseField>

    <ResponseField name="booking_status" type="string">
      Booking lifecycle state. Default `none`.
    </ResponseField>

    <ResponseField name="booking" type="object | null">
      Booking subdocument, or `null`.
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO creation timestamp.
    </ResponseField>

    <ResponseField name="updatedAt" type="string">
      ISO last-update timestamp.
    </ResponseField>

    <ResponseField name="__v" type="number">
      Internal document version.
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  Additional fields may appear on the appointment object. Treat any field not
  documented here as opaque.
</Note>

## Example Request

<RequestExample>
  ```bash curl theme={null}
  curl -X POST "https://app.medisync.me/api/appointments/update/65f8a1b2c3d4e5f6789012ef" \
    -H "Authorization: Bearer <JWT>" \
    -H "Content-Type: application/json" \
    -d '{
      "status": "finished",
      "notes": "Konsultation abgeschlossen"
    }'
  ```
</RequestExample>

## Example Response

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true,
    "data": {
      "_id": "65f8a1b2c3d4e5f6789012ef",
      "name": "Allgemeine Beratung",
      "date": "2026-07-15T00:00:00.000Z",
      "time": "14:30",
      "status": "finished",
      "error_reason": null,
      "doctor_id": "65f0a1b2c3d4e5f678901234",
      "notes": "Konsultation abgeschlossen",
      "language": "de",
      "notes_type": null,
      "appointment_type": "in_person",
      "room": null,
      "duration_minutes": 30,
      "deletionDate": "2026-07-29T00:00:00.000Z",
      "booking_status": "none",
      "booking": null,
      "createdAt": "2026-07-02T09:12:00.000Z",
      "updatedAt": "2026-07-02T10:20:00.000Z",
      "__v": 0
    }
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json 404 Not Found theme={null}
  {
    "success": false,
    "error": "Appointment not found"
  }
  ```

  ```json 403 Forbidden theme={null}
  {
    "success": false,
    "error": "Forbidden"
  }
  ```

  ```json 409 External Appointment Read-only theme={null}
  {
    "success": false,
    "code": "EXTERNAL_APPOINTMENT_READONLY",
    "error": "Externally synced appointments cannot be rescheduled here"
  }
  ```

  ```json 400 Invalid Duration theme={null}
  {
    "success": false,
    "error": "duration_minutes must be between 5 and 480"
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "success": false,
    "message": "Unauthorized"
  }
  ```
</ResponseExample>

<Note>
  `EXTERNAL_APPOINTMENT_READONLY` is returned when the appointment was
  synced from an external booking system and the request tries to change its
  `date`, `time` or `duration_minutes`. `403 Forbidden` is returned when the
  appointment is owned by a different doctor. A missing or invalid Bearer token
  returns `401` with a `message` key.
</Note>
