Kulcare Docs
DeveloperAppointments

Practitioner Unavailability API Documentation

Last Updated: 2026-02-26 API Version: v2 Base URL: https://api.kulcare.com/api/v2


Table of Contents

  1. Overview
  2. Data Model
  3. Endpoints
  4. Error Handling

Overview

The Practitioner Unavailability API allows managing practitioner (doctor) unavailability at specific facilities. This enables:

  • Setting date range unavailability (e.g., vacation, leave)
  • Marking practitioner as unavailable till further notice
  • Checking practitioner availability before appointment booking

Key Features:

  • Practitioner unavailability is scoped to both practitioner AND facility
  • Same practitioner can have different availability at different facilities
  • Soft delete support (clearing unavailability doesn't permanently delete records)

Date semantics

The CMS unavailability form sends two ISO8601 timestamps — start_time and end_time — that the backend stores verbatim and compares against per-day appointment timestamps. Both fields must be anchored to the user's local timezone, not to UTC, or the comparison misses whole calendar days.

The rule:

  • start_time = start of the chosen start date in local time (YYYY-MM-DDT00:00:00.000±HH:MM)
  • end_time = end of the chosen end date in local time (YYYY-MM-DDT23:59:59.999±HH:MM)

A bare date.toISOString() from a Date picker is not enough — toISOString() shifts the calendar day into the previous day in UTC for any user east of UTC. For example, a CMS user in IST (UTC+05:30) who picks 24–25 Sep and sends 2026-09-25T00:00:00.000Z (the bare toISOString of "25 Sep 00:00 IST") would have the backend's end_time land on the start of 25 Sep IST — missing the entire 25 Sep workday. Anchor the end-of-day in local time (setHours(23,59,59,999)) before calling toISOString().

The comparison in AvailabilityService#practitioner_unavailable? is half-open:

exists?(['till_further_notice = ? OR (start_time <= ? AND end_time >= ?)',
        true, appointment_datetime, appointment_datetime])

This works for either convention (inclusive end-of-day or exclusive start-of-next-day) as long as the client picks one and stays consistent. The CMS convention is inclusive end-of-day (set the last day's end_time to 23:59:59.999 local).


Data Model

PractitionerUnavailability

FieldTypeDescription
idUUIDUnique identifier
practitioner_idUUIDReference to practitioner
facility_idUUIDReference to facility
till_further_noticeBooleanIf true, practitioner is unavailable indefinitely
start_timeDateTimeStart of unavailability period (ISO8601). Should be the start-of-day in the user's local timezone (00:00:00).
end_timeDateTimeEnd of unavailability period (ISO8601). Should be the end-of-day in the user's local timezone (23:59:59.999) so the whole end-date is covered. See "Date semantics" below.
deletedBooleanSoft delete flag
deleted_atDateTimeSoft delete timestamp
created_atDateTimeRecord creation timestamp
updated_atDateTimeLast update timestamp

Endpoints

1. Get Practitioner Unavailability

Get the current unavailability status for a practitioner at the current facility.

Endpoint: GET /clinical/practitioners/:practitioner_id/unavailabilities

Authentication: Bearer token required

Example Request:

GET /api/v2/clinical/practitioners/01900004-0000-7000-8000-000000000001/unavailabilities
Authorization: Bearer <token>

Response (200 OK):

{
  "data": {
    "id": "019c1234-5678-90ab-cdef-1234567890ab",
    "created_at": "2026-02-15T09:00:00.000Z",
    "updated_at": "2026-02-15T09:00:00.000Z",
    "till_further_notice": false,
    "start_time": "2026-02-15T09:00:00.000Z",
    "end_time": "2026-02-20T18:00:00.000Z"
  },
  "meta": {
    "request_id": "019c1234-5678-90ab-cdef-1234567890ab"
  }
}

No Unavailability Set Response (200 OK):

{
  "data": {
    "till_further_notice": false,
    "start_time": null,
    "end_time": null
  },
  "meta": {
    "request_id": "019c1234-5678-90ab-cdef-1234567890ab"
  }
}

2. Set Practitioner Unavailability

Set practitioner unavailability (date range or till further notice).

Endpoint: POST /clinical/practitioners/:practitioner_id/unavailabilities

Authentication: Bearer token required

Request Body:

{
  "unavailability": {
    "start_time": "2026-02-15T09:00:00Z",
    "end_time": "2026-02-20T18:00:00Z"
  }
}

Or for till further notice:

{
  "unavailability": {
    "till_further_notice": true
  }
}

Field Descriptions:

FieldTypeRequiredDescription
start_timeISO8601 DateTimeYes*Start of unavailability (required for date range)
end_timeISO8601 DateTimeYes*End of unavailability (required for date range)
till_further_noticeBooleanYes*Mark as unavailable indefinitely

*Either start_time + end_time (date range) OR till_further_notice: true is required.

Response (201 Created):

{
  "data": {
    "id": "019c1234-5678-90ab-cdef-1234567890ab",
    "created_at": "2026-02-15T09:00:00.000Z",
    "updated_at": "2026-02-15T09:00:00.000Z",
    "till_further_notice": false,
    "start_time": "2026-02-15T09:00:00.000Z",
    "end_time": "2026-02-20T18:00:00.000Z"
  },
  "meta": {
    "request_id": "019c1234-5678-90ab-cdef-1234567890ab"
  }
}

Till Further Notice Response (201 Created):

{
  "data": {
    "id": "019c1234-5678-90ab-cdef-1234567890ab",
    "created_at": "2026-02-15T09:00:00.000Z",
    "updated_at": "2026-02-15T09:00:00.000Z",
    "till_further_notice": true,
    "start_time": null,
    "end_time": null
  },
  "meta": {
    "request_id": "019c1234-5678-90ab-cdef-1234567890ab"
  }
}

3. Clear Practitioner Unavailability

Clear/remove practitioner unavailability (soft delete).

Endpoint: DELETE /clinical/practitioners/:practitioner_id/unavailabilities/clear

Authentication: Bearer token required

Example Request:

DELETE /api/v2/clinical/practitioners/01900004-0000-7000-8000-000000000001/unavailabilities/clear
Authorization: Bearer <token>

Response (200 OK):

{
  "data": {
    "till_further_notice": false,
    "start_time": null,
    "end_time": null
  },
  "meta": {
    "request_id": "019c1234-5678-90ab-cdef-1234567890ab"
  }
}

Integration with Appointments

Walk-in Appointments

When creating a walk-in appointment, the system checks:

  • If practitioner is marked as unavailable till further notice → BLOCKED
  • If practitioner's date range unavailability covers today → BLOCKED

Fixed/Telemedicine Appointments

When creating fixed or telemedicine appointments, the system performs full availability check:

  • Practitioner unavailable (till further notice or date range) → BLOCKED
  • Appointment time conflicts with existing appointments → BLOCKED
  • Practitioner not working at facility → BLOCKED

Error Handling

All error responses follow this standard format:

{
  "data": null,
  "error": {
    "code": "error_code",
    "message": "Human-readable error message",
    "details": [
      {
        "field": "field_name",
        "message": "Specific error message"
      }
    ]
  },
  "meta": {
    "request_id": "unique-request-id"
  }
}

Validation Error (422)

{
  "data": null,
  "error": {
    "code": "validation_failed",
    "message": "Must provide either start_time/end_time or till_further_notice",
    "details": [
      {
        "field": "unavailability",
        "message": "Must provide either start_time/end_time or till_further_notice"
      }
    ]
  },
  "meta": {
    "request_id": "abc-123-def-456"
  }
}

Practitioner Not Found (404)

{
  "data": null,
  "error": {
    "code": "not_found",
    "message": "Practitioner not found",
    "details": []
  },
  "meta": {
    "request_id": "abc-123-def-456"
  }
}

Practitioner Not at Facility (422)

{
  "data": null,
  "error": {
    "code": "validation_failed",
    "message": "Practitioner is not active at this facility",
    "details": [
      {
        "field": "practitioner_id",
        "message": "Practitioner is not active at this facility"
      }
    ]
  },
  "meta": {
    "request_id": "abc-123-def-456"
  }
}

Frontend Tips

  1. Facility Context: The API uses the current facility from the authentication token. All unavailability settings are per-practitioner-per-facility.

  2. Date Format: Always use ISO8601 format (e.g., 2026-02-15T09:00:00Z) for date/time fields.

  3. Clearing Unavailability: Use the DELETE endpoint to clear unavailability. Do not use POST with empty params.

  4. Availability Check: Before creating appointments:

    • Call GET endpoint to check current unavailability status
    • Display appropriate messaging to patients if practitioner is unavailable
  5. Displaying Status:

    • till_further_notice: true → Show "Unavailable till further notice"
    • start_time and end_time present → Show date range
    • All null → Show "Available"
  6. Booking Flow:

    • Check unavailability before showing time slots
    • For walk-ins, check if practitioner is available today
    • Block booking if practitioner is unavailable

On this page