Reservaciones
Los endpoints de reservaciones gestionan el ciclo de vida completo de una reservación de evento: creación, consulta, verificación y actualización de estado.
Todos los endpoints requieren autenticación (Authorization: Bearer <token>).
Estados de una reservación
pending ──► completed
──► failed
──► cancelledLos estados completed, failed y cancelled son terminales — no admiten transición.
Endpoints
GET /api/reservations
Lista todas las reservaciones del usuario autenticado, incluyendo datos del evento.
Respuesta exitosa (200):
{
"data": [
{
"id": "uuid",
"status": "completed",
"paypalOrderId": "PAYPAL-ORDER-ID",
"amountPaid": 800,
"currency": "MXN",
"reservedAt": "2025-06-01T20:00:00Z",
"paidAt": "2025-06-01T20:05:00Z",
"event": {
"title": "Retiro de Yoga — Verano 2025",
"eventDate": "2025-07-15T10:00:00Z",
"slug": "retiro-verano-2025",
"priceAmount": 800
}
}
]
}POST /api/reservations
Crea una nueva reservación o reactiva una cancelada/fallida.
Body:
{
"eventSlug": "retiro-verano-2025",
"fullName": "Ana García",
"email": "ana@email.com"
}Respuesta: 201 (nueva) o 200 (reactivada).
Lógica de upsert:
- Resuelve el
event_iddesde el slug - Hace upsert del usuario en la tabla
users(porclerk_user_id) - Si existe una reservación en estado
cancelled,failedopending: la reactiva apending - Si no existe: inserta nueva reservación
Error 409: Ya existe una reservación activa (completed o pending nuevo) para este evento/usuario.
GET /api/reservations/check?slug=<slug>
Verifica si el usuario autenticado tiene una reservación activa para el evento indicado.
Parámetro: slug (query string) — slug del evento.
Respuesta exitosa (200):
{
"data": {
"hasReservation": true,
"status": "pending",
"reservationId": "uuid"
}
}El frontend usa este endpoint al abrir el modal de reservación para determinar si ir directo al paso de pago.
PATCH /api/reservations/:id
Actualiza el estado de una reservación. Valida que la transición sea permitida.
Body:
{
"status": "completed",
"paypalOrderId": "PAYPAL-ORDER-ID",
"amountPaid": 800,
"currency": "MXN",
"paidAt": "2025-06-01T20:05:00Z"
}Solo status es requerido. Los demás campos son opcionales y se incluyen al completar un pago.
Error 422: Transición no permitida (ej. intentar volver a pending desde completed).
Integración con el frontend
El ReservationModal llama a estos endpoints en este orden:
1. Abrir modal → GET /api/reservations/check?slug=...
↳ hasReservation: false → mostrar formulario
↳ status: "pending" → ir directo al paso de pago
↳ status: "completed" → mostrar mensaje "ya reservado"
2. Submit form → POST /api/reservations
↳ guarda reservationId en estado local
3. PayPal → POST /api/paypal/create-order (ver sección PayPal)
4. Captura → POST /api/paypal/capture-order
↳ actualiza la reservación a "completed" internamente