The Appointments API powers the complete booking lifecycle in MELIKA. Patients can reserve time slots with a specific doctor and specialty, view their upcoming and past appointments, render a FullCalendar-compatible event feed, cancel a booking with a stated reason, and permanently delete cancelled records. Every route is protected by JWT authentication, and the database layer enforces slot availability with concurrency-safe triggers that prevent double-booking even under simultaneous requests.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Imjuanisss/proyecto-melika/llms.txt
Use this file to discover all available pages before exploring further.
State Machine
Every appointment begins inpendiente and moves through a strict set of transitions. Patients control cancellation and deletion; doctors and administrators control completion and no-show recording.
| Current State | Allowed Transition | Triggered By |
|---|---|---|
pendiente | → completada | Doctor / Admin |
pendiente | → no_asistio | Doctor / Admin |
pendiente | → cancelada | Patient / Admin |
cancelada | → (deleted) | Patient |
Once an appointment is marked
completada or no_asistio it cannot be modified or cancelled through the patient-facing API. Only cancelada appointments may be permanently deleted.Authentication
All/citas routes require a valid JWT passed in the Authorization header via the verifyToken middleware. The authenticated user’s identity is used automatically — patients always operate on their own data only.
Endpoints
POST /citas — Create Appointment
Books a new appointment for the authenticated patient. The server looks up the doctor’s tarifa (fee) automatically and inserts the record with estado = 'pendiente'. The target franja_horaria (time slot) is locked during the insert to prevent concurrent double-bookings.
Authentication: Authorization: Bearer <token> — required
Request Body
Unique identifier of the doctor to book. The doctor must exist and have an active status; otherwise a
404 NOT_FOUND is returned.Identifier of the medical specialty for this appointment.
Identifier of the time slot (
franja_horaria) to reserve. The slot must exist and be currently available. If it does not exist the DB trigger raises PgSQL error 45001 (INVALID_SLOT); if it is already taken by a concurrent booking, error 45002 (CONCURRENCY_CONFLICT) is raised.Appointment date in
YYYY-MM-DD format.Appointment start time in
HH:MM (24-hour) format.Consultation modality. Accepted values:
presencial or teleconsulta.Optional free-text reason or chief complaint for the appointment.
Response — 201 Created
Human-readable confirmation message:
"Cita reservada exitosamente."The newly created appointment record.
Error Codes
| HTTP Status | Code | Cause |
|---|---|---|
400 | BAD_REQUEST | One or more required body fields are missing. |
400 | INVALID_SLOT | The id_franja does not exist (PgSQL 45001). |
404 | NOT_FOUND | Doctor with id_medico not found or marked inactive. |
409 | CONCURRENCY_CONFLICT | Another patient booked the same slot simultaneously (PgSQL 45002). |
401 | UNAUTHORIZED | JWT missing or invalid. |
Example
GET /citas/mis-citas — List My Appointments
Returns all appointments belonging to the authenticated patient, ordered by date and start time (most recent first). Includes doctor name, specialty, and time-slot end time resolved from the franjas_horarias table.
Authentication: Authorization: Bearer <token> — required
Request Parameters
No query or path parameters required. The patient is identified from the JWT automatically.Response — 200 OK
An array of appointment objects, ordered by fecha DESC, hora_inicio DESC.
Error Codes
| HTTP Status | Code | Cause |
|---|---|---|
401 | UNAUTHORIZED | JWT missing or invalid. |
Example
GET /citas/calendario — Calendar Events
Returns a list of appointment events formatted for direct consumption by FullCalendar. cancelada appointments are excluded. If no date range is supplied, the response defaults to events within the current calendar month.
Authentication: Authorization: Bearer <token> — required
Query Parameters
Start of the date range in
YYYY-MM-DD format. Also accepted as start (FullCalendar’s default param name). Defaults to the first day of the current month if omitted.End of the date range in
YYYY-MM-DD format. Also accepted as end. Defaults to the last day of the current month if omitted.Response — 200 OK
An array of FullCalendar-compatible event objects. cancelada appointments are never included.
Error Codes
| HTTP Status | Code | Cause |
|---|---|---|
401 | UNAUTHORIZED | JWT missing or invalid. |
Example
PATCH /citas/:id — Cancel Appointment
Cancels a pendiente appointment owned by the authenticated patient. A razon_cancelacion is required in the request body. The cancellation atomically updates the appointment state and — via a database trigger — automatically sets the corresponding franja_horaria.disponible = TRUE, making the slot immediately available for other patients without any additional API call.
Automatic Slot Liberation: The database trigger that releases the time slot fires on every
UPDATE that sets estado = 'cancelada'. The slot is freed in the same transaction as the cancellation — there is no race window where the slot appears taken after a successful cancellation response.Authorization: Bearer <token> — required
Path Parameters
The appointment identifier to cancel.
Request Body
The patient’s stated reason for cancelling. Must be a non-blank string in the request body (not a query parameter).
Response — 200 OK
Confirmation message:
"Cita cancelada. La franja horaria fue liberada automáticamente por la base de datos."The full updated appointment record reflecting
estado = 'cancelada' and the recorded razon_cancelacion.Error Codes
| HTTP Status | Code | Cause |
|---|---|---|
400 | BAD_REQUEST | razon_cancelacion missing or blank in request body. |
400 | BAD_REQUEST | Appointment is already cancelada. |
400 | BAD_REQUEST | Appointment is completada and cannot be cancelled. |
403 | FORBIDDEN | The appointment belongs to a different patient. |
404 | NOT_FOUND | No appointment found with the given id. |
401 | UNAUTHORIZED | JWT missing or invalid. |
Example
DELETE /citas/:id — Delete Appointment
Permanently removes a cancelada appointment record belonging to the authenticated patient. Only cancelled appointments may be deleted — this prevents accidental loss of active or completed booking history.
Authentication: Authorization: Bearer <token> — required
Path Parameters
The appointment identifier to delete. Must be in
cancelada state.Response — 200 OK
Confirmation:
"Cita eliminada correctamente."Error Codes
| HTTP Status | Code | Cause |
|---|---|---|
400 | BAD_REQUEST | Appointment state is not cancelada (e.g., still pendiente or completada). |
403 | FORBIDDEN | The appointment belongs to a different patient. |
404 | NOT_FOUND | No appointment found with the given id. |
401 | UNAUTHORIZED | JWT missing or invalid. |
Example
Full Booking Flow
The following example walks through the end-to-end lifecycle: creating a new appointment, confirming it appears on the calendar, then cancelling and deleting it.Book an appointment
Reserve a slot by
POSTing to /citas. Store the returned cita.id for subsequent calls.Verify on the calendar
Fetch the calendar for the target month. The new appointment appears with the
pendiente amber fill (#B45309) and darker amber border (#92400E).Cancel the appointment
Cancel with a reason in the request body. The database trigger fires and frees the slot automatically.