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

# Update Session

> Partially update a session (appointment) by its public id, scoped to the authenticated organization. Any subset of fields may be sent; each is overlaid on the stored session and the MERGED final state is validated with the exact same rules as create. Time changes require date, startTime, endTime and timezone together.

## Update Session

Partially update a single session (appointment) by its public id, scoped to the organization that owns the API key. All referenced entities (staff, client, clinician, location, provider location, non-billable code, service lines) must belong to that organization.

### Headers

```
Authorization: Bearer <your-api-key>
Content-Type: application/json
```

### Merge-then-validate

A PATCH is a **partial** update. Every field you send is overlaid on the stored session, and the resulting **merged** state is validated with the **exact same rules as create**. A PATCH can therefore never leave a session in a shape that create would reject.

* Omit a field to leave it unchanged.
* Send `null` for a nullable reference (`clientId`, `clinicianId`, `providerLocationId`, `nonBillableCodeId`) to clear it.
* `services` **replaces** the current service. Send `null` to make the session non-billable — you must then also provide `nonBillableCodeId`.

Because the merged state is validated as a whole, the billable/non-billable rules still apply after the merge:

* **Billable** (merged state has `services`): `clientId` and `clinicianId` must be present, and it is mutually exclusive with `nonBillableCodeId`.
* **Non-billable** (merged state has `nonBillableCodeId`): mutually exclusive with `services`; supervision requires `clinicianId`, while a standard (non-supervision) non-billable session must not have a `clinicianId`.
* **Telehealth**: allowed only on billable sessions and requires `providerLocationId`.

### Frozen sessions

A session that already has recorded clinical work cannot be edited (nor deleted), mirroring the calendar. Any of the following freezes the session and makes a PATCH return `400`:

* a non-archived **encounter**,
* a non-archived **note** (activity),
* a **completed cancellation**.

Cancellations still mid-workflow (pending, searching, etc.) do not freeze the session.

### Time fields

To change the time, send `date`, `startTime`, `endTime` and `timezone` **together**. Sending only some of them is rejected with `400` (`To change the time, provide date, startTime, endTime and timezone together.`). When all four are provided, they are combined into UTC instants:

* `date` — `YYYY-MM-DD`, a real calendar date.
* `startTime` / `endTime` — `HH:mm` or `HH:mm:ss`. `endTime` must be after `startTime`, and the total duration must not exceed 8 hours.
* `timezone` — IANA zone (for example `America/New_York`).

### Session status

`status` changes the scheduling status of the session.

* Allowed values: `CONFIRMED`, `UNCONFIRMED`, `DECLINED`, `PATIENT_NO_SHOW`, `REQUESTED_TO_CANCEL`.
* **Omit `status` to leave the stored value unchanged**, so a patch of unrelated fields never re-confirms a session that was declined or marked a no-show. Unlike create, there is no default on update.
* Values are matched exactly (uppercase). Any other value returns a `400`.
* The response includes the session's current `status` after the update.

### Success Response (200)

Returns the updated session in the same discriminated shape as create and get — billable sessions expose `isBillable: true`, `isTelehealth`, `clinicianId`, `providerLocationId` and `services`; non-billable sessions expose `isBillable: false` and `nonBillableCode` instead.

```json theme={null}
{
  "publicId": "apt_1a2b3c4d5e",
  "title": "John Doe — Adaptive behavior treatment",
  "status": "CONFIRMED",
  "startTime": "2026-01-05T14:00:00.000Z",
  "endTime": "2026-01-05T15:00:00.000Z",
  "isSupervision": false,
  "isClientPresent": true,
  "placeOfService": "HOME",
  "locationId": "loc_1a2b3c",
  "technicianId": "usr_tech123",
  "clientId": "usr_client789",
  "isBillable": true,
  "isTelehealth": false,
  "clinicianId": "usr_clin456",
  "providerLocationId": "loc_9f8e7d",
  "services": "svc_1a2b3c"
}
```

### Error Responses

#### 400 - Bad Request

Returned when the session is frozen (it has a non-archived encounter, a non-archived note, or a completed cancellation), when the merged state violates a validation rule (billable/non-billable requirements, telehealth without a provider location, `endTime` not after `startTime`, total duration over 8 hours compared at second precision, an invalid calendar date, place of service not allowed by a service line, a `technicianId` whose role cannot deliver a session, a `clientId` that is not a patient, a `clinicianId` that is not a clinical role, or a technician on a non-technician service line), or when a referenced entity does not exist in the organization.

Business-rule rejections — a frozen session, or a merged state that violates a billable/non-billable, telehealth, time, place-of-service, staff-role or referenced-entity rule — are returned as a plain error (no validation list):

```json theme={null}
{
  "error": "Cannot modify or delete a session that has encounters.",
  "statusCode": 400
}
```

Malformed field input caught before the business rules (bad enum, empty string, invalid date pattern, a partial time change, a non-nullable field sent as `null`) is returned as a validation list instead (each `path` is an array of segments):

```json theme={null}
{
  "message": "Validation Error",
  "statusCode": 400,
  "validationErrors": [
    {
      "code": "custom",
      "path": ["date"],
      "message": "To change the time, provide date, startTime, endTime and timezone together."
    }
  ]
}
```

#### 401 - Unauthorized

```json theme={null}
{
  "error": "API key required",
  "statusCode": 401
}
```

#### 403 - Forbidden

```json theme={null}
{
  "error": "Access denied",
  "statusCode": 403
}
```

#### 404 - Not Found

```json theme={null}
{
  "error": "Session not found",
  "statusCode": 404
}
```

## Examples

### Reschedule a session (cURL)

```bash theme={null}
curl -X PATCH "https://app.hipp.health/api/v1/sessions/apt_1a2b3c4d5e" \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-01-06",
    "startTime": "13:00",
    "endTime": "14:00",
    "timezone": "America/New_York"
  }'
```

### Convert a billable session to non-billable (cURL)

```bash theme={null}
curl -X PATCH "https://app.hipp.health/api/v1/sessions/apt_1a2b3c4d5e" \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "services": null,
    "clinicianId": null,
    "nonBillableCodeId": "nbc_1a2b3c"
  }'
```

### JavaScript Example

```javascript theme={null}
const updateSession = async (sessionId, patch) => {
  const response = await fetch(
    `https://app.hipp.health/api/v1/sessions/${sessionId}`,
    {
      method: "PATCH",
      headers: {
        Authorization: "Bearer your-api-key",
        "Content-Type": "application/json",
      },
      body: JSON.stringify(patch),
    }
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error || error.message || "Failed to update session");
  }

  return response.json();
};

// Usage
try {
  const session = await updateSession("apt_1a2b3c4d5e", {
    title: "Renamed session",
    isClientPresent: true,
  });
  console.log("Updated session:", session);
} catch (error) {
  console.error("Error updating session:", error.message);
}
```


## OpenAPI

````yaml PATCH /v1/sessions/{sessionId}
openapi: 3.0.0
info:
  title: Hipp Health API
  version: 1.0.0
  description: API for managing users and resources within your Hipp Health organization
servers:
  - url: https://app.hipp.health/api
    description: Production Server
security: []
paths:
  /v1/sessions/{sessionId}:
    patch:
      tags:
        - V1
      summary: Update session by id
      description: >-
        Partially update a session (appointment) by its public id, scoped to the
        authenticated organization. Any subset of fields may be sent; each is
        overlaid on the stored session and the MERGED final state is validated
        with the exact same rules as create. Time changes require date,
        startTime, endTime and timezone together.
      operationId: patch-v1-session-by-id
      parameters:
        - name: sessionId
          in: path
          description: Session public identifier
          required: true
          schema:
            type: string
            minLength: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSessionRequest'
      responses:
        '200':
          description: Session updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'
        '400':
          description: >-
            Bad Request. Either the session is frozen (it has a non-archived
            encounter, a non-archived note, or a completed cancellation) or the
            merged state failed validation.
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    description: Frozen-session rejection.
                    properties:
                      error:
                        type: string
                        example: Cannot modify or delete a session that has encounters.
                      statusCode:
                        type: integer
                        example: 400
                  - $ref: '#/components/schemas/ValidationError'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Session not found
                  statusCode:
                    type: integer
                    example: 404
        '405':
          $ref: '#/components/responses/405'
      security:
        - BearerAuth: []
components:
  schemas:
    UpdateSessionRequest:
      type: object
      description: >-
        Partial update for a single session. Any subset of fields may be sent;
        each is overlaid on the stored session and the MERGED final state is
        validated with the exact same rules as create, so a PATCH can never
        leave a session in a shape create would reject. Nullable reference
        fields (clientId, clinicianId, providerLocationId, nonBillableCodeId)
        accept null to clear the reference; omit a field to leave it unchanged.
        Time changes require date, startTime, endTime and timezone together.
      properties:
        technicianId:
          type: string
          minLength: 1
          description: >-
            Public id of the staff member delivering the session. Must be a
            staff role (TECHNICIAN, CLINICIAN, CLINICAL_ADMIN or
            CLINICAL_SUPERADMIN). A TECHNICIAN can only be assigned to
            technician-only service lines.
          example: usr_tech123
        clientId:
          type: string
          minLength: 1
          nullable: true
          description: >-
            Public id of the client. Must reference a patient. Send null to
            clear. Required on the merged state when the session is billable.
          example: usr_client789
        clinicianId:
          type: string
          minLength: 1
          nullable: true
          description: >-
            Public id of the clinician. Must reference a clinician or clinical
            admin. Send null to clear. Required on the merged state for billable
            sessions and for non-billable supervision sessions.
          example: usr_clin456
        date:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: >-
            Calendar date (YYYY-MM-DD). Must be a real calendar date. Provide
            together with startTime, endTime and timezone to change the time.
          example: '2026-01-05'
        startTime:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$
          description: >-
            Wall-clock start time (HH:mm or HH:mm:ss). Only applied when date,
            startTime, endTime and timezone are all sent together.
          example: '09:00'
        endTime:
          type: string
          pattern: ^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$
          description: >-
            Wall-clock end time (HH:mm or HH:mm:ss). Must be after startTime,
            and the total duration must not exceed 8 hours.
          example: '10:00'
        timezone:
          type: string
          minLength: 1
          description: IANA timezone used to interpret date/startTime/endTime.
          example: America/New_York
        locationId:
          type: string
          minLength: 1
          description: Public id of the session location.
          example: loc_1a2b3c
        providerLocationId:
          type: string
          minLength: 1
          nullable: true
          description: >-
            Public id of the location the provider delivers from. Send null to
            clear. Required on the merged state when isTelehealth is true.
          example: loc_9x8y7z
        services:
          type: string
          minLength: 1
          nullable: true
          description: >-
            Public id of the billable service line. Replaces the current
            service. Send null to clear it (making the merged session
            non-billable, which then requires nonBillableCodeId); omit to leave
            it unchanged.
          example: svc_1a2b3c
        nonBillableCodeId:
          type: string
          minLength: 1
          nullable: true
          description: >-
            Public id of the non-billable code. Send null to clear. Mutually
            exclusive with a billable (services) merged state.
          example: nbc_1a2b3c
        placeOfService:
          $ref: '#/components/schemas/PlaceOfServiceCode'
        isTelehealth:
          type: boolean
          description: >-
            Whether the session is delivered via telehealth. Only allowed on
            billable sessions and requires providerLocationId on the merged
            state.
        isSupervision:
          type: boolean
          description: >-
            Whether the session is a supervision session. For non-billable
            supervision, clinicianId is required on the merged state.
        isClientPresent:
          type: boolean
          description: Whether the client is present for the session.
        title:
          type: string
          minLength: 1
          description: Custom title. When provided, replaces the stored title.
        status:
          allOf:
            - $ref: '#/components/schemas/AppointmentStatus'
          description: >-
            New scheduling status for the session. Omit to leave the stored
            status unchanged, so a patch of unrelated fields never re-confirms a
            session that was declined or marked a no-show. Matched exactly
            (uppercase); any other value returns a 400.
    Session:
      description: >-
        A scheduled session (appointment). The shape depends on isBillable:
        billable sessions expose isTelehealth, clinicianId and services;
        non-billable sessions expose nonBillableCode instead.
      oneOf:
        - $ref: '#/components/schemas/BillableSession'
        - $ref: '#/components/schemas/NonBillableSession'
      discriminator:
        propertyName: isBillable
    ValidationError:
      type: object
      required:
        - message
        - statusCode
        - validationErrors
      properties:
        message:
          type: string
          example: Validation Error
        statusCode:
          type: integer
          example: 400
        validationErrors:
          type: array
          description: Zod validation issues
          items:
            type: object
            properties:
              code:
                type: string
                example: invalid_type
              message:
                type: string
                example: Required
              path:
                type: array
                items:
                  oneOf:
                    - type: string
                    - type: integer
                example:
                  - email
    PlaceOfServiceCode:
      type: string
      enum:
        - TELEHEALTH_PROVIDED_ELSEWHERE
        - TELEHEALTH_PROVIDED_IN_PATIENT_HOME
        - OFFICE
        - HOME
        - SCHOOL
        - OTHER
        - TEMPORARY_LODGING
        - PLACE_OF_EMPLOYMENT
        - COMMUNITY_MENTAL_HEALTH_CENTER
      description: CMS place-of-service classification for the session
    AppointmentStatus:
      type: string
      enum:
        - CONFIRMED
        - UNCONFIRMED
        - DECLINED
        - PATIENT_NO_SHOW
        - REQUESTED_TO_CANCEL
      description: >-
        Scheduling status of the session. Matched exactly (uppercase); any other
        value returns a 400.
    BillableSession:
      allOf:
        - $ref: '#/components/schemas/SessionBase'
        - type: object
          properties:
            isBillable:
              type: boolean
              enum:
                - true
              description: Always true for billable sessions.
            isTelehealth:
              type: boolean
              example: false
            clinicianId:
              type: string
              nullable: true
              description: Public id of the assigned clinician, if any.
              example: usr_clin456
            providerLocationId:
              type: string
              nullable: true
              description: >-
                Public id of the provider location the care was delivered from,
                if any.
              example: loc_9f8e7d
            services:
              type: string
              description: >-
                Public id of the billable service line rendered. A session bills
                exactly one service line.
              example: svc_1a2b3c
          required:
            - isBillable
            - isTelehealth
            - clinicianId
            - providerLocationId
            - services
    NonBillableSession:
      allOf:
        - $ref: '#/components/schemas/SessionBase'
        - type: object
          properties:
            isBillable:
              type: boolean
              enum:
                - false
              description: Always false for non-billable sessions.
            nonBillableCode:
              type: string
              description: Public id of the non-billable code.
              example: nbc_1a2b3c
          required:
            - isBillable
            - nonBillableCode
    ApiErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message
          example: User not found
        statusCode:
          type: integer
          example: 404
      required:
        - error
        - statusCode
    SessionBase:
      type: object
      properties:
        publicId:
          type: string
          example: apt_1a2b3c4d5e
        title:
          type: string
          example: John Doe — Adaptive behavior treatment
        status:
          $ref: '#/components/schemas/AppointmentStatus'
        startTime:
          type: string
          format: date-time
          description: Session start instant in UTC (ISO-8601).
          example: '2026-01-05T14:00:00.000Z'
        endTime:
          type: string
          format: date-time
          description: Session end instant in UTC (ISO-8601).
          example: '2026-01-05T15:00:00.000Z'
        isSupervision:
          type: boolean
          example: false
        isClientPresent:
          type: boolean
          example: true
        placeOfService:
          $ref: '#/components/schemas/PlaceOfServiceCode'
        locationId:
          type: string
          description: Public id of the session location.
          example: loc_1a2b3c
        technicianId:
          type: string
          nullable: true
          description: Public id of the assigned technician, if any.
          example: usr_tech123
        clientId:
          type: string
          nullable: true
          description: Public id of the client, if any.
          example: usr_client789
      required:
        - publicId
        - title
        - status
        - startTime
        - endTime
        - isSupervision
        - isClientPresent
        - placeOfService
        - locationId
        - technicianId
        - clientId
  responses:
    '401':
      description: Unauthorized - API key required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            error: API key required
            statusCode: 401
    '403':
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            error: Access denied
            statusCode: 403
    '405':
      description: Method Not Allowed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            error: Method not allowed
            statusCode: 405
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        API key authentication. Include your API key in the Authorization header
        as 'Bearer <your-api-key>'

````