Practitioner Unavailability API Documentation
Last Updated: 2026-02-26
API Version: v2
Base URL: https://api.kulcare.com/api/v2
Table of Contents
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
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
practitioner_id | UUID | Reference to practitioner |
facility_id | UUID | Reference to facility |
till_further_notice | Boolean | If true, practitioner is unavailable indefinitely |
start_time | DateTime | Start of unavailability period (ISO8601). Should be the start-of-day in the user's local timezone (00:00:00). |
end_time | DateTime | End 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. |
deleted | Boolean | Soft delete flag |
deleted_at | DateTime | Soft delete timestamp |
created_at | DateTime | Record creation timestamp |
updated_at | DateTime | Last 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:
| Field | Type | Required | Description |
|---|---|---|---|
start_time | ISO8601 DateTime | Yes* | Start of unavailability (required for date range) |
end_time | ISO8601 DateTime | Yes* | End of unavailability (required for date range) |
till_further_notice | Boolean | Yes* | 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
-
Facility Context: The API uses the current facility from the authentication token. All unavailability settings are per-practitioner-per-facility.
-
Date Format: Always use ISO8601 format (e.g.,
2026-02-15T09:00:00Z) for date/time fields. -
Clearing Unavailability: Use the DELETE endpoint to clear unavailability. Do not use POST with empty params.
-
Availability Check: Before creating appointments:
- Call GET endpoint to check current unavailability status
- Display appropriate messaging to patients if practitioner is unavailable
-
Displaying Status:
till_further_notice: true→ Show "Unavailable till further notice"start_timeandend_timepresent → Show date range- All null → Show "Available"
-
Booking Flow:
- Check unavailability before showing time slots
- For walk-ins, check if practitioner is available today
- Block booking if practitioner is unavailable