API Contract: Bookings¶
Proposito¶
Contrato de la API de reservas de turnos: busqueda de disponibilidad, reserva, cancelacion, y consulta de turnos.
Metadata¶
| Campo | Valor |
|---|---|
| Recurso | Bookings / Availability |
| Base URL | /api/v1/bookings, /api/v1/doctors |
| Autor | Carlos Ramirez |
| Fecha | 2025-03-25 |
| Estado | Agreed |
| Spec relacionada | feature-booking-system.spec.md |
Convenciones Generales¶
Autenticacion¶
Bearer token JWT. Todos los endpoints requieren autenticacion.
Paginacion¶
Cursor-based: ?cursor=<lastId>&limit=20
Fechas y horas¶
- Fechas en formato
YYYY-MM-DD. - Horas en formato
HH:mm. - Timestamps en ISO 8601 UTC (
2025-03-20T10:30:00Z). - Los horarios de slots se muestran en la zona horaria de la clinica.
Endpoints¶
GET /api/v1/doctors¶
Descripcion: Lista medicos con filtros de especialidad y clinica.
Autorizacion: Cualquier usuario autenticado.
Query params: | Param | Tipo | Requerido | Default | Descripcion | |-------|------|-----------|---------|-------------| | specialtyId | UUID | No | - | Filtrar por especialidad | | clinicId | UUID | No | - | Filtrar por clinica | | name | string | No | - | Buscar por nombre (parcial) | | cursor | UUID | No | - | ID del ultimo resultado | | limit | integer | No | 20 | Max resultados (1-50) |
Response exitosa:
Status: 200 OK
{
"data": [
{
"id": "d1a2b3c4-...",
"firstName": "Ana",
"lastName": "Garcia",
"licenseNumber": "MN-12345",
"specialties": [
{
"id": "s1a2b3c4-...",
"name": "Cardiologia"
}
],
"clinics": [
{
"id": "c1a2b3c4-...",
"name": "Clinica San Martin",
"address": "Av. Corrientes 1234, CABA"
}
],
"nextAvailableSlot": "2025-03-22T09:00:00-03:00"
}
],
"pagination": {
"nextCursor": "d1a2b3c4-...",
"hasMore": true
}
}
GET /api/v1/doctors/:doctorId/availability¶
Descripcion: Retorna los slots disponibles de un medico en un rango de fechas.
Autorizacion: Cualquier usuario autenticado.
Path params: | Param | Tipo | Requerido | Descripcion | |-------|------|-----------|-------------| | doctorId | UUID | Si | ID del medico |
Query params: | Param | Tipo | Requerido | Default | Descripcion | |-------|------|-----------|---------|-------------| | dateFrom | date | Si | - | Fecha inicio (YYYY-MM-DD) | | dateTo | date | Si | - | Fecha fin (YYYY-MM-DD) | | clinicId | UUID | No | - | Filtrar por clinica | | specialtyId | UUID | No | - | Filtrar por especialidad |
Response exitosa:
Status: 200 OK
{
"data": {
"doctor": {
"id": "d1a2b3c4-...",
"firstName": "Ana",
"lastName": "Garcia"
},
"slots": [
{
"date": "2025-03-22",
"startTime": "09:00",
"endTime": "09:30",
"clinicId": "c1a2b3c4-...",
"clinicName": "Clinica San Martin",
"timezone": "America/Argentina/Buenos_Aires"
},
{
"date": "2025-03-22",
"startTime": "09:30",
"endTime": "10:00",
"clinicId": "c1a2b3c4-...",
"clinicName": "Clinica San Martin",
"timezone": "America/Argentina/Buenos_Aires"
}
]
}
}
Responses de error:
| Status | Code | Cuando |
|---|---|---|
| 400 | INVALID_DATE_RANGE | dateFrom > dateTo o rango > 30 dias |
| 404 | DOCTOR_NOT_FOUND | El medico no existe |
POST /api/v1/bookings¶
Descripcion: Crea una nueva reserva de turno.
Autorizacion: PATIENT.
Request:
Body:
{
"doctorId": "d1a2b3c4-...",
"clinicId": "c1a2b3c4-...",
"specialtyId": "s1a2b3c4-...",
"date": "2025-03-22",
"startTime": "09:00"
}
| Campo | Tipo | Requerido | Descripcion |
|---|---|---|---|
| doctorId | UUID | Si | ID del medico |
| clinicId | UUID | Si | ID de la clinica |
| specialtyId | UUID | Si | ID de la especialidad |
| date | date | Si | Fecha del turno (YYYY-MM-DD) |
| startTime | time | Si | Hora de inicio (HH:mm) |
Response exitosa:
Status: 201 Created
{
"data": {
"id": "b1a2b3c4-...",
"patientId": "p1a2b3c4-...",
"doctor": {
"id": "d1a2b3c4-...",
"firstName": "Ana",
"lastName": "Garcia"
},
"clinic": {
"id": "c1a2b3c4-...",
"name": "Clinica San Martin",
"address": "Av. Corrientes 1234, CABA"
},
"specialty": {
"id": "s1a2b3c4-...",
"name": "Cardiologia"
},
"date": "2025-03-22",
"startTime": "09:00",
"endTime": "09:30",
"status": "CONFIRMED",
"createdAt": "2025-03-20T15:30:00Z"
},
"message": "Turno reservado exitosamente."
}
Responses de error:
| Status | Code | Cuando |
|---|---|---|
| 400 | VALIDATION_ERROR | Datos invalidos o faltantes |
| 400 | SLOT_TOO_SOON | Menos de 2h de anticipacion |
| 403 | PATIENT_BLOCKED | Paciente bloqueado por penalizaciones |
| 409 | SLOT_ALREADY_BOOKED | El slot ya fue reservado por otro paciente |
| 409 | DUPLICATE_BOOKING | El paciente ya tiene turno con ese medico hoy |
GET /api/v1/bookings¶
Descripcion: Lista los turnos del usuario autenticado.
Autorizacion: PATIENT (ve sus turnos), DOCTOR (ve su agenda), ADMIN (ve todos).
Query params: | Param | Tipo | Requerido | Default | Descripcion | |-------|------|-----------|---------|-------------| | status | string | No | - | Filtrar por status (CONFIRMED, CANCELLED, etc.) | | dateFrom | date | No | hoy | Fecha inicio | | dateTo | date | No | +30 dias | Fecha fin | | cursor | UUID | No | - | Paginacion | | limit | integer | No | 20 | Max resultados |
Response exitosa:
Status: 200 OK
{
"data": [
{
"id": "b1a2b3c4-...",
"doctor": {
"id": "d1a2b3c4-...",
"firstName": "Ana",
"lastName": "Garcia"
},
"clinic": {
"id": "c1a2b3c4-...",
"name": "Clinica San Martin"
},
"specialty": {
"name": "Cardiologia"
},
"date": "2025-03-22",
"startTime": "09:00",
"endTime": "09:30",
"status": "CONFIRMED",
"createdAt": "2025-03-20T15:30:00Z"
}
],
"pagination": {
"nextCursor": "b1a2b3c4-...",
"hasMore": false
}
}
GET /api/v1/bookings/:bookingId¶
Descripcion: Retorna el detalle de un turno especifico.
Autorizacion: El paciente dueno, el medico asignado, o un admin.
Response exitosa:
Status: 200 OK
{
"data": {
"id": "b1a2b3c4-...",
"patientId": "p1a2b3c4-...",
"doctor": {
"id": "d1a2b3c4-...",
"firstName": "Ana",
"lastName": "Garcia",
"licenseNumber": "MN-12345"
},
"clinic": {
"id": "c1a2b3c4-...",
"name": "Clinica San Martin",
"address": "Av. Corrientes 1234, CABA",
"timezone": "America/Argentina/Buenos_Aires"
},
"specialty": {
"id": "s1a2b3c4-...",
"name": "Cardiologia"
},
"date": "2025-03-22",
"startTime": "09:00",
"endTime": "09:30",
"status": "CONFIRMED",
"cancellationPenalty": false,
"createdAt": "2025-03-20T15:30:00Z"
}
}
Responses de error:
| Status | Code | Cuando |
|---|---|---|
| 403 | FORBIDDEN | El usuario no tiene acceso a este booking |
| 404 | BOOKING_NOT_FOUND | El booking no existe |
PATCH /api/v1/bookings/:bookingId/cancel¶
Descripcion: Cancela un turno.
Autorizacion: El paciente dueno o el medico asignado.
Request:
Body:
| Campo | Tipo | Requerido | Descripcion |
|---|---|---|---|
| reason | string | No | Motivo de cancelacion |
Response exitosa:
Status: 200 OK
{
"data": {
"id": "b1a2b3c4-...",
"status": "CANCELLED",
"cancelledAt": "2025-03-21T10:00:00Z",
"cancellationPenalty": true,
"penaltyCount": 1,
"message": "Turno cancelado. Se aplico penalizacion por cancelacion tardia (menos de 24h)."
}
}
Responses de error:
| Status | Code | Cuando |
|---|---|---|
| 400 | BOOKING_NOT_CANCELLABLE | El booking no esta en status CONFIRMED |
| 403 | FORBIDDEN | El usuario no tiene permiso para cancelar |
| 404 | BOOKING_NOT_FOUND | El booking no existe |
Codigos de Error Especificos¶
| Code | HTTP Status | Descripcion |
|---|---|---|
| SLOT_ALREADY_BOOKED | 409 | El slot fue reservado por otro paciente |
| SLOT_TOO_SOON | 400 | Menos de 2h de anticipacion |
| DUPLICATE_BOOKING | 409 | Ya tiene turno con ese medico hoy |
| PATIENT_BLOCKED | 403 | Paciente bloqueado por penalizaciones |
| BOOKING_NOT_CANCELLABLE | 400 | No se puede cancelar (ya completado/cancelado) |
| DOCTOR_NOT_FOUND | 404 | Medico no existe |
| BOOKING_NOT_FOUND | 404 | Booking no existe |
| INVALID_DATE_RANGE | 400 | Rango de fechas invalido |
Checklist de Completitud¶
- Todos los endpoints documentados
- Request y response con ejemplos concretos
- Errores documentados con codigos especificos
- Autorizacion especificada por endpoint
- Paginacion documentada
- Revisada por frontend team
- Revisada por otro ingeniero backend
- Derivados generados (test plan / OpenAPI spec)
Archivos relacionados¶
- _template.api.md - Plantilla
- api-users.md - API de usuarios
- ../01-specs/feature-booking-system.spec.md - Spec de reservas
- ../03-domain-model/domain-booking.md - Modelo de dominio
- ../05-testing-strategy/bdd-scenarios-booking.md - Escenarios BDD