Doctors API
import { Badge } from ‘@astrojs/starlight/components’;
Doctors
Section titled “Doctors”GET /api/doctors
Section titled “GET /api/doctors”List all active doctors for the clinic.
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 /api/doctors/:id/availability
Section titled “GET /api/doctors/:id/availability”Get available appointment slots for a doctor on a specific date.
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.
POST /api/doctors
Section titled “POST /api/doctors”Create a new doctor.
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 |
PUT /api/doctors/:id
Section titled “PUT /api/doctors/:id”Update a doctor’s profile and working hours.
Request: Same shape as POST plus is_active: true|false. Working hours are replaced (delete all, insert new).
Response 200: Updated doctor object
DELETE /api/doctors/:id
Section titled “DELETE /api/doctors/:id”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 /api/calendar/feed-url/:doctorId
Section titled “GET /api/calendar/feed-url/:doctorId”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"}GET /api/calendar/open/:token
Section titled “GET /api/calendar/open/:token”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
GET /api/calendar/feed/:token.ics
Section titled “GET /api/calendar/feed/:token.ics”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)