Skip to content

Doctors API

import { Badge } from ‘@astrojs/starlight/components’;

List all active doctors for the clinic.

Auth: Required

Query params: page (default 1), limit (default 50)

Response 200:

{
"doctors": [
{
"id": "uuid",
"clinic_id": "uuid",
"full_name": "Dr. Juan García",
"specialty": "Medicina General",
"bio": "Médico con 15 años de experiencia...",
"photo_url": "https://...",
"consultation_duration_minutes": 30,
"buffer_time_minutes": 10,
"is_active": true,
"doctor_working_hours": [
{
"id": "uuid",
"day_of_week": 1,
"start_time": "09:00:00",
"end_time": "17:00:00",
"is_active": true
}
],
"doctor_breaks": [
{
"id": "uuid",
"day_of_week": 1,
"start_time": "12:00:00",
"end_time": "13:00:00"
}
]
}
],
"total": 3,
"page": 1,
"limit": 50
}

Get available appointment slots for a doctor on a specific date.

Auth: Required

Query params: date (YYYY-MM-DD, required)

Response 200:

[
{ "startTime": "09:00", "endTime": "09:30" },
{ "startTime": "09:40", "endTime": "10:10" },
{ "startTime": "10:20", "endTime": "10:50" }
]

Slots exclude: outside working hours, break times, vacations, already-booked slots, and times in the past.

Slot duration = consultation_duration_minutes. Gap between slots = buffer_time_minutes.


Create a new doctor.

Auth: Admin only (enforced by checkDoctorLimit)

Request:

{
"fullName": "Dr. María López",
"specialty": "Dermatología",
"bio": "Especialista en enfermedades de la piel...",
"consultationDurationMinutes": 45,
"bufferTimeMinutes": 15,
"workingHours": [
{ "dayOfWeek": 1, "startTime": "09:00", "endTime": "17:00" },
{ "dayOfWeek": 3, "startTime": "09:00", "endTime": "17:00" }
]
}

dayOfWeek: 0 = Sunday, 1 = Monday, … 6 = Saturday

Response 201: Doctor object with id

Errors:

Status Code Reason
403 DOCTOR_LIMIT_REACHED Plan doctor limit exceeded
503 Cannot verify limit (DB error) — fail closed

Update a doctor’s profile and working hours.

Auth: Admin only

Request: Same shape as POST plus is_active: true|false. Working hours are replaced (delete all, insert new).

Response 200: Updated doctor object


Deactivate a doctor (soft delete).

Auth: Admin only

Sets is_active: false and clears calendar_feed_token. The doctor’s historical appointments remain intact.

Response 200:

{ "message": "Doctor deactivated successfully" }

Get calendar subscription URLs for a doctor.

Auth: Required

Generates a calendar_feed_token (64-char hex) on first call if none exists.

Response 200:

{
"doctorId": "uuid",
"doctorName": "Dr. García",
"openUrl": "https://api.clinicflow.lat/api/calendar/open/abc123...def789",
"feedUrl": "https://api.clinicflow.lat/api/calendar/feed/abc123...def789.ics",
"webcalUrl": "webcal://api.clinicflow.lat/api/calendar/feed/abc123...def789.ics"
}

Smart redirect to add the calendar:

  • iOS: webcal:// (opens native Calendar app)
  • Android/Other: Google Calendar “Add from URL” dialog

Auth: None (public) Rate limit: 30 req / 15 min / IP

Response: 302 Redirect


Download the ICS calendar file.

Auth: None (public) Rate limit: 30 req / 15 min / IP

Returns RFC 5545 iCalendar with the doctor’s confirmed + pending appointments (last 7 days → next 90 days). Only patient first name is included (privacy). No phone numbers, emails, or DUI numbers.

Response: text/calendar; charset=utf-8


POST /api/calendar/feed-url/:doctorId/regenerate

Section titled “POST /api/calendar/feed-url/:doctorId/regenerate”

Regenerate the calendar feed token, invalidating the previous URL.

Auth: Admin only

Response 200: New feed URLs (same format as GET feed-url)