Today's Appointments
0
Total Patients
0
Upcoming (7 days)
0
Cancellation Rate
0%

Appointments

Time Patient Doctor Status Reason Actions

Doctor Schedule

This Week

Patients

ID Name Phone Date of Birth Gender Email Appointments

API Documentation

Base URL: /api/v1 — Auth: Authorization: Bearer <key> or X-API-Key: <key>

Specialties

GET/api/v1/specialties — List all specialties
Example Response
{
  "specialties": [
    { "id": "spec_001", "name": "Cardiology", "description": "Heart and vascular system" },
    { "id": "spec_002", "name": "Dermatology", "description": "Skin, hair, and nail conditions" }
  ]
}

Doctors

GET/api/v1/doctors?specialty_id=&name=&available_on= — Search doctors
Example: Search by specialty
GET /api/v1/doctors?specialty_id=spec_001
// Response 200
{
  "doctors": [
    {
      "id": "doc_001",
      "name": "Dr. Sari Wijaya, Sp.JP",
      "specialty": { "id": "spec_001", "name": "Cardiology" },
      "hospital": { "id": "hosp_001", "name": "RS Mekari Sehat - Jakarta" },
      "consultation_fee": 350000,
      "bio": "Cardiologist with 15 years of experience...",
      "languages": ["id", "en"],
      "photo_url": "https://ui-avatars.com/api/?name=Dr.+Sari+Wijaya",
      "next_available_slot": "2026-05-22T10:00:00+07:00"
    }
  ]
}
GET/api/v1/doctors/{doctor_id}/slots?from=&to=&status= — Get available slots
Example: Get slots for a doctor
GET /api/v1/doctors/doc_001/slots?from=2026-05-22&to=2026-05-22
// Response 200
{
  "doctor_id": "doc_001",
  "slots": [
    { "id": "slot_0042", "doctor_id": "doc_001", "start_time": "2026-05-22T10:00:00+07:00", "end_time": "2026-05-22T10:30:00+07:00", "status": "available" },
    { "id": "slot_0043", "doctor_id": "doc_001", "start_time": "2026-05-22T10:30:00+07:00", "end_time": "2026-05-22T11:00:00+07:00", "status": "available" }
  ]
}

Patients

POST/api/v1/patients — Register new patient
Example: Register a patient
POST /api/v1/patients
Content-Type: application/json

{
  "full_name": "Budi Santoso",
  "phone": "+628123456789",
  "date_of_birth": "1985-03-12",
  "gender": "male",
  "email": "budi@example.com"
}
// Response 201
{
  "patient": {
    "id": "pat_0004",
    "full_name": "Budi Santoso",
    "phone": "+628123456789",
    "date_of_birth": "1985-03-12",
    "gender": "male",
    "email": "budi@example.com",
    "created_at": "2026-05-19T14:33:00+07:00"
  }
}
// Error 409 — phone already registered
{
  "error": {
    "code": "PATIENT_ALREADY_EXISTS",
    "message": "A patient with this phone number is already registered",
    "details": { "patient_id": "pat_0001" }
  }
}
GET/api/v1/patients/lookup?phone= — Look up patient by phone
Example: Lookup patient
GET /api/v1/patients/lookup?phone=%2B628123456789
// Response 200
{
  "patient": {
    "id": "pat_0001",
    "full_name": "Budi Santoso",
    "phone": "+628123456789",
    "date_of_birth": "1985-03-12",
    "gender": "male",
    "email": "budi.santoso@email.com",
    "created_at": "2026-05-19T14:00:00+07:00"
  }
}
// Error 404 — not found
{
  "error": { "code": "PATIENT_NOT_FOUND", "message": "No patient found with this phone number" }
}

Appointments

POST/api/v1/appointments — Book appointment
Example: Book an appointment
POST /api/v1/appointments
Content-Type: application/json

{
  "patient_id": "pat_0001",
  "doctor_id": "doc_001",
  "slot_id": "slot_0042",
  "reason_for_visit": "Chest pain and shortness of breath for 2 weeks"
}
// Response 201
{
  "appointment": {
    "id": "appt_00003",
    "patient": { "id": "pat_0001", "full_name": "Budi Santoso", "phone": "+628123456789" },
    "doctor": { "id": "doc_001", "name": "Dr. Sari Wijaya, Sp.JP", "specialty": "Cardiology" },
    "slot": { "id": "slot_0042", "start_time": "2026-05-22T10:00:00+07:00", "end_time": "2026-05-22T10:30:00+07:00" },
    "status": "confirmed",
    "reason_for_visit": "Chest pain and shortness of breath for 2 weeks",
    "created_at": "2026-05-19T14:33:00+07:00",
    "updated_at": "2026-05-19T14:33:00+07:00"
  }
}
// Error 409 — slot taken
{ "error": { "code": "SLOT_UNAVAILABLE", "message": "Selected slot is no longer available" } }

// Error 409 — patient has overlapping appointment
{
  "error": {
    "code": "PATIENT_HAS_CONFLICT",
    "message": "Patient already has an appointment at this time",
    "details": { "conflicting_appointment": { "id": "appt_00001", "..." : "..." } }
  }
}

// Error 400 — slot in the past
{ "error": { "code": "SLOT_IN_PAST", "message": "Cannot book a slot in the past" } }
GET/api/v1/appointments?patient_id=&status=&from=&to= — List appointments
Example: List patient appointments
GET /api/v1/appointments?patient_id=pat_0001&status=confirmed
// Response 200
{
  "appointments": [
    {
      "id": "appt_00001",
      "patient": { "id": "pat_0001", "full_name": "Budi Santoso", "phone": "+628123456789" },
      "doctor": { "id": "doc_001", "name": "Dr. Sari Wijaya, Sp.JP", "specialty": "Cardiology" },
      "slot": { "id": "slot_0001", "start_time": "2026-05-22T08:00:00+07:00", "end_time": "2026-05-22T08:30:00+07:00" },
      "status": "confirmed",
      "reason_for_visit": "Chest pain and shortness of breath for 2 weeks",
      "created_at": "2026-05-19T14:00:00+07:00",
      "updated_at": "2026-05-19T14:00:00+07:00"
    }
  ]
}
GET/api/v1/appointments/{id} — Get appointment detail
Example: Get appointment detail
GET /api/v1/appointments/appt_00001
// Response 200
{
  "appointment": {
    "id": "appt_00001",
    "patient": { "id": "pat_0001", "full_name": "Budi Santoso", "phone": "+628123456789" },
    "doctor": { "id": "doc_001", "name": "Dr. Sari Wijaya, Sp.JP", "specialty": "Cardiology" },
    "slot": { "id": "slot_0001", "start_time": "2026-05-22T08:00:00+07:00", "end_time": "2026-05-22T08:30:00+07:00" },
    "status": "confirmed",
    "reason_for_visit": "Chest pain and shortness of breath for 2 weeks",
    "cancellation_reason": null,
    "created_at": "2026-05-19T14:00:00+07:00",
    "updated_at": "2026-05-19T14:00:00+07:00"
  }
}
PATCH/api/v1/appointments/{id} — Reschedule (change slot)
Example: Reschedule an appointment
PATCH /api/v1/appointments/appt_00001
Content-Type: application/json

{
  "slot_id": "slot_0055"
}
// Response 200
{
  "appointment": {
    "id": "appt_00001",
    "patient": { "id": "pat_0001", "full_name": "Budi Santoso", "phone": "+628123456789" },
    "doctor": { "id": "doc_001", "name": "Dr. Sari Wijaya, Sp.JP", "specialty": "Cardiology" },
    "slot": { "id": "slot_0055", "start_time": "2026-05-26T09:00:00+07:00", "end_time": "2026-05-26T09:30:00+07:00" },
    "status": "rescheduled",
    "reason_for_visit": "Chest pain and shortness of breath for 2 weeks",
    "created_at": "2026-05-19T14:00:00+07:00",
    "updated_at": "2026-05-19T15:20:00+07:00"
  }
}
// Error 409 — new slot not available
{ "error": { "code": "SLOT_UNAVAILABLE", "message": "Selected slot is no longer available" } }

// Error 400 — cannot reschedule cancelled appointment
{ "error": { "code": "CANNOT_RESCHEDULE_CANCELLED_APPOINTMENT", "message": "Cannot reschedule a cancelled appointment" } }

// Error 400 — appointment is in the past
{ "error": { "code": "CANNOT_RESCHEDULE_PAST_APPOINTMENT", "message": "Cannot reschedule a past appointment" } }
DELETE/api/v1/appointments/{id} — Cancel appointment
Example: Cancel an appointment
DELETE /api/v1/appointments/appt_00001
Content-Type: application/json

{
  "reason": "Patient feels better and no longer needs visit"
}
// Response 200
{
  "appointment": {
    "id": "appt_00001",
    "patient": { "id": "pat_0001", "full_name": "Budi Santoso", "phone": "+628123456789" },
    "doctor": { "id": "doc_001", "name": "Dr. Sari Wijaya, Sp.JP", "specialty": "Cardiology" },
    "slot": { "id": "slot_0001", "start_time": "2026-05-22T08:00:00+07:00", "end_time": "2026-05-22T08:30:00+07:00" },
    "status": "cancelled",
    "reason_for_visit": "Chest pain and shortness of breath for 2 weeks",
    "cancellation_reason": "Patient feels better and no longer needs visit",
    "created_at": "2026-05-19T14:00:00+07:00",
    "updated_at": "2026-05-19T16:00:00+07:00"
  }
}

Utility

POST/api/v1/reset — Reset demo data
Example: Reset demo
POST /api/v1/reset
// Response 200
{
  "message": "Demo data reset successfully",
  "summary": { "slots": 608, "patients": 3, "appointments": 2 }
}
GET/api/v1/hospitals — Hospital info
Example: Get hospital info
GET /api/v1/hospitals
// Response 200
{
  "hospitals": [
    {
      "id": "hosp_001",
      "name": "RS Mekari Sehat - Jakarta",
      "address": "Jl. Jend. Sudirman Kav. 52-53, Senayan, Jakarta Selatan 12190",
      "phone": "+6221-5551234",
      "operating_hours": {
        "monday": "08:00-17:00", "tuesday": "08:00-17:00", "wednesday": "08:00-17:00",
        "thursday": "08:00-17:00", "friday": "08:00-17:00", "saturday": "08:00-13:00",
        "sunday": "Closed"
      }
    }
  ]
}
GET/health — Health check (no auth)
Example: Health check
GET /health
// Response 200
{ "status": "ok", "auth_enabled": false }

Error Format

{
  "error": {
    "code": "SLOT_UNAVAILABLE",
    "message": "Selected slot is no longer available",
    "details": {}
  }
}

Error codes: SLOT_UNAVAILABLE, SLOT_IN_PAST, PATIENT_ALREADY_EXISTS, PATIENT_NOT_FOUND, PATIENT_HAS_CONFLICT, CANNOT_RESCHEDULE_CANCELLED_APPOINTMENT, CANNOT_RESCHEDULE_PAST_APPOINTMENT, ALREADY_CANCELLED, VALIDATION_ERROR, UNAUTHORIZED