API de Reservas
Referencia completa para gestionar reservas y reservaciones de cenotes.
Descripción General
La API de Reservas maneja el ciclo completo de reservaciones para visitas a cenotes, desde la creación inicial de la reserva hasta la confirmación, modificación y cancelación. Esta API se integra con sistemas de pago y gestión de capacidad.
Endpoints
Listar Reservas
Obtén reservas con filtrado y paginación.
GET /api/partner/reservations
Parámetros
| Parámetro | Tipo | Requerido | Descripción | Ejemplo |
|---|---|---|---|---|
page | integer | No | Número de página (por defecto: 1) | ?page=1 |
perPage | integer | No | Elementos por página (por defecto: 15, máx: 100) | ?perPage=20 |
cursor | string | No | Cursor para paginación basada en cursor | ?cursor=eyJpZCI6InJlc18xMjM0In0 |
status | string | No | Filtrar por estado | ?status=confirmed |
cenoteId | string | No | Filtrar por ID de cenote | ?cenoteId=c3n0t3-1234 |
guestEmail | string | No | Filtrar por email del huésped | ?guestEmail=guest@example.com |
dateFrom | string | No | Filtrar desde fecha (ISO 8601) | ?dateFrom=2024-07-01 |
dateTo | string | No | Filtrar hasta fecha (ISO 8601) | ?dateTo=2024-07-31 |
createdAfter | string | No | Filtrar por fecha de creación | ?createdAfter=2024-01-01 |
sortBy | string | No | Campo de ordenamiento | ?sortBy=visitDate |
sortDirection | string | No | Dirección de ordenamiento (asc o desc) | ?sortDirection=desc |
expand | string | No | Recursos relacionados a incluir | ?expand=cenote,guest |
Valores de Estado
| Estado | Descripción |
|---|---|
pending | Reserva creada, esperando pago |
confirmed | Pago recibido, reserva confirmada |
cancelled | Reserva cancelada |
no_show | El huésped no se presentó |
completed | Visita completada exitosamente |
refunded | Reserva reembolsada |
Ejemplo de Solicitud
curl -X GET "https://service-gateway.loscenotes.com/api/partner/reservations?status=confirmed&dateFrom=2024-07-15" \
-H "X-API-Key: sk_test_your_api_key" \
-H "Content-Type: application/json"
Ejemplo de Respuesta
{
"success": true,
"message": "reservations.list_retrieved_successfully",
"data": [
{
"id": "res_1234567890abcdef",
"bookingReference": "LC-2024-001234",
"status": "confirmed",
"cenoteId": "c3n0t3-1234-5678-90ab",
"visitDate": "2024-07-15",
"visitTime": "10:00",
"visitors": {
"total": 4,
"breakdown": {
"adults": 2,
"children": 2,
"seniors": 0
}
},
"guest": {
"name": "John Smith",
"email": "john@example.com",
"phone": "+1-555-123-4567",
"nationality": "US",
"emergencyContact": {
"name": "Jane Smith",
"phone": "+1-555-987-6543"
}
},
"pricing": {
"subtotal": 1100,
"taxes": 176,
"fees": 50,
"total": 1326,
"currency": "MXN",
"breakdown": [
{
"type": "adult",
"quantity": 2,
"unitPrice": 350,
"total": 700
},
{
"type": "child",
"quantity": 2,
"unitPrice": 200,
"total": 400
}
],
"discounts": [
{
"type": "group_discount",
"name": "Descuento grupal de 4+",
"amount": 110,
"percentage": 0.1
}
]
},
"payment": {
"id": "pay_abcd1234",
"status": "completed",
"method": "credit_card",
"provider": "stripe",
"transactionId": "txn_stripe_123456",
"paidAt": "2024-07-10T14:30:00Z"
},
"services": [
{
"id": "srv_guide_001",
"name": "Guía Profesional",
"type": "guide",
"price": 150,
"duration": 120,
"included": false
},
{
"id": "srv_transport_001",
"name": "Recogida en Hotel",
"type": "transport",
"price": 300,
"pickup": {
"location": "Hotel Xcaret",
"time": "08:00"
},
"included": false
}
],
"specialRequests": "Opción de almuerzo vegetariano para 2 personas",
"notes": {
"internal": "Visitantes primerizos, se necesita orientación extra",
"guest": "Celebrando aniversario"
},
"cancellation": {
"allowed": true,
"deadline": "2024-07-13T23:59:59Z",
"policy": {
"fullRefund": "48_hours",
"partialRefund": "24_hours",
"noRefund": "same_day"
}
},
"confirmationSent": true,
"reminderSent": false,
"checkIn": null,
"cenote": {
"id": "c3n0t3-1234-5678-90ab",
"name": "Cenote Dos Ojos",
"location": {
"latitude": 20.327423,
"longitude": -87.382118,
"address": "Carretera Tulum-Coba Km 5.5"
},
"contact": {
"phone": "+52 984 123 4567"
}
},
"metadata": {
"source": "website",
"userAgent": "Mozilla/5.0...",
"referrer": "https://google.com",
"affiliateId": null
},
"createdAt": "2024-07-10T14:25:00Z",
"updatedAt": "2024-07-10T14:30:00Z"
}
],
"pagination": {
"total": 156,
"perPage": 15,
"currentPage": 1,
"lastPage": 11,
"hasNextPage": true,
"hasPreviousPage": false
}
}
Crear Reserva
Crea una nueva reserva de cenote.
POST /api/partner/reservations
Cuerpo de la Solicitud
{
"cenoteId": "c3n0t3-1234-5678-90ab",
"visitDate": "2024-07-15",
"visitTime": "10:00",
"visitors": {
"adults": 2,
"children": 2,
"seniors": 0
},
"guest": {
"name": "John Smith",
"email": "john@example.com",
"phone": "+1-555-123-4567",
"nationality": "US",
"dateOfBirth": "1985-03-15",
"emergencyContact": {
"name": "Jane Smith",
"phone": "+1-555-987-6543",
"relationship": "spouse"
}
},
"services": [
{
"id": "srv_guide_001",
"quantity": 1
},
{
"id": "srv_transport_001",
"pickup": {
"location": "Hotel Xcaret",
"time": "08:00"
}
}
],
"specialRequests": "Opción de almuerzo vegetariano para 2 personas",
"promoCode": "SUMMER2024",
"metadata": {
"source": "mobile_app",
"affiliateId": "partner_123"
}
}
Descripción de Campos
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
cenoteId | string | Sí | UUID del cenote |
visitDate | string | Sí | Fecha de visita (YYYY-MM-DD) |
visitTime | string | No | Horario preferido (HH:MM) |
visitors | object | Sí | Conteo de visitantes por tipo |
guest | object | Sí | Información del huésped principal |
services | array | No | Servicios adicionales |
specialRequests | string | No | Solicitudes especiales o notas |
promoCode | string | No | Código promocional |
metadata | object | No | Metadatos adicionales |
Ejemplo de Solicitud
curl -X POST "https://service-gateway.loscenotes.com/api/partner/reservations" \
-H "X-API-Key: sk_test_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"cenoteId": "c3n0t3-1234-5678-90ab",
"visitDate": "2024-07-15",
"visitTime": "10:00",
"visitors": {
"adults": 2,
"children": 2
},
"guest": {
"name": "John Smith",
"email": "john@example.com",
"phone": "+1-555-123-4567"
}
}'
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.created_successfully",
"data": {
"id": "res_1234567890abcdef",
"bookingReference": "LC-2024-001234",
"status": "pending",
"cenoteId": "c3n0t3-1234-5678-90ab",
"visitDate": "2024-07-15",
"visitTime": "10:00",
"visitors": {
"total": 4,
"breakdown": {
"adults": 2,
"children": 2,
"seniors": 0
}
},
"pricing": {
"subtotal": 1100,
"taxes": 176,
"fees": 50,
"total": 1326,
"currency": "MXN",
"breakdown": [
{
"type": "adult",
"quantity": 2,
"unitPrice": 350,
"total": 700
},
{
"type": "child",
"quantity": 2,
"unitPrice": 200,
"total": 400
}
]
},
"payment": {
"required": true,
"deadline": "2024-07-12T23:59:59Z",
"methods": ["credit_card", "paypal", "cash"],
"instructions": {
"creditCard": {
"url": "https://checkout.loscenotes.com/pay/res_1234567890abcdef"
}
}
},
"cancellation": {
"allowed": true,
"deadline": "2024-07-13T23:59:59Z",
"policy": {
"fullRefund": "48_hours",
"partialRefund": "24_hours",
"noRefund": "same_day"
}
},
"confirmationCode": "LC001234",
"qrCode": {
"url": "https://service-gateway.loscenotes.com/api/partner/reservations/res_1234567890abcdef/qr",
"data": "loscenotes://reservation/res_1234567890abcdef"
},
"createdAt": "2024-07-10T14:25:00Z",
"expiresAt": "2024-07-12T23:59:59Z"
}
}
Obtener Detalles de Reserva
Obtén información detallada sobre una reserva específica.
GET /api/partner/reservations/{id}
Parámetros
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | ID de reserva o referencia de reserva |
expand | string | No | Recursos relacionados a incluir |
Opciones de Expansión
| Valor | Descripción |
|---|---|
cenote | Incluir información completa del cenote |
payment | Incluir información detallada del pago |
services | Incluir detalles completos de servicios |
reviews | Incluir reseñas de huéspedes (si está completada) |
Ejemplo de Solicitud
curl -X GET "https://service-gateway.loscenotes.com/api/partner/reservations/res_1234567890abcdef?expand=cenote,payment" \
-H "X-API-Key: sk_test_your_api_key"
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.retrieved_successfully",
"data": {
"id": "res_1234567890abcdef",
"bookingReference": "LC-2024-001234",
"status": "confirmed",
"statusHistory": [
{
"status": "pending",
"timestamp": "2024-07-10T14:25:00Z",
"note": "Reserva creada"
},
{
"status": "confirmed",
"timestamp": "2024-07-10T14:30:00Z",
"note": "Pago recibido"
}
],
"timeline": {
"created": "2024-07-10T14:25:00Z",
"paymentDeadline": "2024-07-12T23:59:59Z",
"cancellationDeadline": "2024-07-13T23:59:59Z",
"visitDate": "2024-07-15T10:00:00Z",
"completionDeadline": "2024-07-15T23:59:59Z"
},
"documents": [
{
"type": "confirmation",
"name": "Confirmación de Reserva",
"url": "https://documents.loscenotes.com/confirmations/res_1234567890abcdef.pdf",
"generatedAt": "2024-07-10T14:30:00Z"
},
{
"type": "ticket",
"name": "Boleto de Entrada",
"url": "https://documents.loscenotes.com/tickets/res_1234567890abcdef.pdf",
"qrCode": "https://service-gateway.loscenotes.com/api/partner/reservations/res_1234567890abcdef/qr"
}
],
"communications": [
{
"type": "confirmation_email",
"status": "sent",
"sentAt": "2024-07-10T14:31:00Z",
"recipient": "john@example.com"
},
{
"type": "reminder_sms",
"status": "scheduled",
"scheduledFor": "2024-07-14T18:00:00Z",
"recipient": "+1-555-123-4567"
}
],
"modifications": {
"allowed": true,
"deadline": "2024-07-13T23:59:59Z",
"allowedChanges": ["visitTime", "visitorCount", "services"],
"restrictions": ["La fecha de visita no se puede cambiar dentro de 48 horas"]
}
}
}
Actualizar Reserva
Modifica una reserva existente.
PATCH /api/partner/reservations/{id}
Cuerpo de la Solicitud
{
"visitTime": "14:00",
"visitors": {
"adults": 3,
"children": 1
},
"specialRequests": "Requisitos dietéticos actualizados: opciones sin gluten necesarias",
"guest": {
"phone": "+1-555-999-8888"
},
"services": [
{
"id": "srv_photography_001",
"quantity": 1,
"action": "add"
},
{
"id": "srv_guide_001",
"action": "remove"
}
]
}
Acciones de Servicios
| Acción | Descripción |
|---|---|
add | Agregar un nuevo servicio |
remove | Eliminar un servicio existente |
update | Actualizar parámetros de servicio |
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.updated_successfully",
"data": {
"id": "res_1234567890abcdef",
"changes": [
{
"field": "visitTime",
"oldValue": "10:00",
"newValue": "14:00"
},
{
"field": "visitors.adults",
"oldValue": 2,
"newValue": 3
},
{
"field": "services",
"added": ["srv_photography_001"],
"removed": ["srv_guide_001"]
}
],
"pricing": {
"previousTotal": 1326,
"newTotal": 1485,
"difference": 159,
"currency": "MXN"
},
"payment": {
"additionalPaymentRequired": true,
"amount": 159,
"deadline": "2024-07-13T23:59:59Z",
"paymentUrl": "https://checkout.loscenotes.com/pay/res_1234567890abcdef/additional"
}
}
}
Confirmar Reserva
Confirma una reserva pendiente (típicamente después del pago).
POST /api/partner/reservations/{id}/confirm
Cuerpo de la Solicitud
{
"paymentId": "pay_abcd1234",
"paymentMethod": "credit_card",
"transactionId": "txn_stripe_123456",
"confirmationEmail": true,
"generateDocuments": true
}
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.confirmed_successfully",
"data": {
"id": "res_1234567890abcdef",
"status": "confirmed",
"confirmationCode": "LC001234",
"payment": {
"id": "pay_abcd1234",
"status": "completed",
"confirmedAt": "2024-07-10T14:30:00Z"
},
"documents": {
"confirmation": "https://documents.loscenotes.com/confirmations/res_1234567890abcdef.pdf",
"ticket": "https://documents.loscenotes.com/tickets/res_1234567890abcdef.pdf"
},
"communications": {
"confirmationEmail": {
"sent": true,
"sentAt": "2024-07-10T14:31:00Z"
}
}
}
}
Cancelar Reserva
Cancela una reserva existente.
POST /api/partner/reservations/{id}/cancel
Cuerpo de la Solicitud
{
"reason": "guest_request",
"note": "Cambio de planes de viaje",
"refund": {
"requested": true,
"method": "original_payment_method",
"amount": "auto"
},
"notifyGuest": true
}
Razones de Cancelación
| Razón | Descripción |
|---|---|
guest_request | Cancelación iniciada por el huésped |
weather | Cancelación relacionada con el clima |
maintenance | Mantenimiento del cenote requerido |
capacity_issue | Problema de capacidad o disponibilidad |
force_majeure | Circunstancias imprevistas |
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.cancelled_successfully",
"data": {
"id": "res_1234567890abcdef",
"status": "cancelled",
"cancellation": {
"reason": "guest_request",
"cancelledAt": "2024-07-12T10:15:00Z",
"cancelledBy": "guest",
"note": "Cambio de planes de viaje"
},
"refund": {
"eligible": true,
"amount": 1195.4,
"fees": 130.6,
"processingTime": "5-10 días hábiles",
"refundId": "ref_xyz789",
"status": "processing"
},
"communications": {
"cancellationEmail": {
"sent": true,
"sentAt": "2024-07-12T10:16:00Z"
}
}
}
}
Check-In de Huésped
Marca a un huésped como registrado para su reserva.
POST /api/partner/reservations/{id}/checkin
Cuerpo de la Solicitud
{
"checkedInAt": "2024-07-15T10:05:00Z",
"actualVisitors": {
"adults": 2,
"children": 2
},
"staff": {
"name": "Maria Rodriguez",
"id": "staff_456"
},
"notes": "Los huéspedes llegaron a tiempo, se proporcionó briefing de seguridad"
}
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.checked_in_successfully",
"data": {
"id": "res_1234567890abcdef",
"status": "in_progress",
"checkIn": {
"checkedInAt": "2024-07-15T10:05:00Z",
"expectedDeparture": "2024-07-15T12:05:00Z",
"actualVisitors": {
"adults": 2,
"children": 2
},
"staff": {
"name": "Maria Rodriguez",
"id": "staff_456"
}
}
}
}
Completar Visita
Marca una reserva como completada después de la visita del huésped.
POST /api/partner/reservations/{id}/complete
Cuerpo de la Solicitud
{
"completedAt": "2024-07-15T12:30:00Z",
"actualDuration": 150,
"feedback": {
"requestReview": true,
"followUpEmail": true
},
"staff": {
"name": "Maria Rodriguez",
"id": "staff_456"
},
"notes": "Excelente experiencia, huéspedes muy satisfechos"
}
Ejemplo de Respuesta
{
"success": true,
"message": "reservation.completed_successfully",
"data": {
"id": "res_1234567890abcdef",
"status": "completed",
"completion": {
"completedAt": "2024-07-15T12:30:00Z",
"actualDuration": 150,
"totalVisitTime": "10:05-12:30"
},
"reviewRequest": {
"sent": true,
"link": "https://reviews.loscenotes.com/res_1234567890abcdef",
"expires": "2024-08-15T23:59:59Z"
}
}
}
Modelos de Datos
Objeto Reservation
interface Reservation {
id: string; // Identificador UUID
bookingReference: string; // Referencia legible para humanos
status: ReservationStatus; // Estado actual
cenoteId: string; // UUID del cenote
visitDate: string; // Fecha de visita (YYYY-MM-DD)
visitTime: string; // Horario (HH:MM)
visitors: VisitorCount; // Desglose de visitantes
guest: Guest; // Información del huésped principal
pricing: PricingBreakdown; // Cálculo de precios
payment?: Payment; // Información de pago
services?: Service[]; // Servicios adicionales
specialRequests?: string; // Solicitudes especiales
notes?: Notes; // Notas internas/del huésped
cancellation?: Cancellation; // Política de cancelación
checkIn?: CheckIn; // Información de check-in
timeline?: Timeline; // Fechas importantes
documents?: Document[]; // Documentos generados
communications?: Communication[]; // Historial de email/SMS
metadata?: Metadata; // Metadatos adicionales
createdAt: string; // Marca de tiempo de creación
updatedAt: string; // Marca de tiempo de última actualización
}
Objeto Guest
interface Guest {
name: string; // Nombre completo
email: string; // Dirección de email
phone: string; // Número de teléfono
nationality?: string; // Código de país (ISO 3166)
dateOfBirth?: string; // Fecha de nacimiento
emergencyContact?: EmergencyContact; // Contacto de emergencia
preferences?: GuestPreferences; // Preferencias del huésped
loyaltyMember?: LoyaltyInfo; // Información del programa de lealtad
}
interface EmergencyContact {
name: string; // Nombre del contacto
phone: string; // Teléfono del contacto
relationship: string; // Relación con el huésped
}
Objeto PricingBreakdown
interface PricingBreakdown {
subtotal: number; // Antes de impuestos y comisiones
taxes: number; // Monto de impuestos
fees: number; // Comisiones de servicio
total: number; // Total final
currency: string; // Código de moneda ISO
breakdown: PriceItem[]; // Desglose detallado
discounts?: Discount[]; // Descuentos aplicados
}
interface PriceItem {
type: "adult" | "child" | "senior" | "service"; // Tipo de elemento
name?: string; // Nombre del elemento
quantity: number; // Cantidad
unitPrice: number; // Precio por unidad
total: number; // Total para este elemento
}
Respuestas de Error
Reserva No Encontrada
{
"success": false,
"error": {
"code": "RESERVATION_NOT_FOUND",
"message": "La reserva solicitada no fue encontrada",
"status": 404,
"details": {
"reservationId": "invalid-id"
}
}
}
Cenote No Disponible
{
"success": false,
"error": {
"code": "CENOTE_NOT_AVAILABLE",
"message": "El cenote no está disponible para la fecha y hora seleccionadas",
"status": 422,
"details": {
"cenoteId": "c3n0t3-1234",
"date": "2024-07-15",
"time": "10:00",
"reason": "fully_booked",
"alternatives": [
{
"date": "2024-07-15",
"time": "14:00",
"available": true
},
{
"date": "2024-07-16",
"time": "10:00",
"available": true
}
]
}
}
}
Capacidad Insuficiente
{
"success": false,
"error": {
"code": "INSUFFICIENT_CAPACITY",
"message": "No hay capacidad suficiente para el número de visitantes solicitado",
"status": 422,
"details": {
"requested": 8,
"available": 3,
"cenoteId": "c3n0t3-1234",
"date": "2024-07-15",
"time": "10:00"
}
}
}
Modificación No Permitida
{
"success": false,
"error": {
"code": "MODIFICATION_NOT_ALLOWED",
"message": "La reserva no puede ser modificada en este momento",
"status": 422,
"details": {
"reason": "too_close_to_visit_date",
"deadline": "2024-07-13T23:59:59Z",
"currentTime": "2024-07-14T10:00:00Z"
}
}
}
Ejemplos de SDK
SDK de TypeScript
import { LosCenotesClient } from "@loscenotes/partner-sdk";
const client = new LosCenotesClient({
apiKey: "sk_test_your_api_key",
environment: "sandbox",
});
// Crear reserva
const reservation = await client.reservations.create({
cenoteId: "c3n0t3-1234",
visitDate: "2024-07-15",
visitTime: "10:00",
visitors: {
adults: 2,
children: 2,
},
guest: {
name: "John Smith",
email: "john@example.com",
phone: "+1-555-123-4567",
},
});
// Obtener reserva
const reservationDetails = await client.reservations.get(
"res_1234567890abcdef",
{ expand: ["cenote", "payment"] }
);
// Actualizar reserva
const updated = await client.reservations.update("res_1234567890abcdef", {
visitTime: "14:00",
visitors: { adults: 3, children: 1 },
});
// Confirmar reserva
const confirmed = await client.reservations.confirm("res_1234567890abcdef", {
paymentId: "pay_abcd1234",
paymentMethod: "credit_card",
});
// Cancelar reserva
const cancelled = await client.reservations.cancel("res_1234567890abcdef", {
reason: "guest_request",
note: "Cambio de planes de viaje",
refund: { requested: true },
});
SDK de Python
from loscenotes import LosCenotesClient
client = LosCenotesClient(
api_key='sk_test_your_api_key',
environment='sandbox'
)
# Crear reserva
reservation = client.reservations.create({
'cenote_id': 'c3n0t3-1234',
'visit_date': '2024-07-15',
'visit_time': '10:00',
'visitors': {
'adults': 2,
'children': 2
},
'guest': {
'name': 'John Smith',
'email': 'john@example.com',
'phone': '+1-555-123-4567'
}
})
# Listar reservas
reservations = client.reservations.list(
status='confirmed',
date_from='2024-07-01',
expand=['cenote']
)
SDK de PHP
<?php
use LosCenotes\LosCenotesClient;
$client = new LosCenotesClient([
'apiKey' => 'sk_test_your_api_key',
'environment' => 'sandbox'
]);
// Crear reserva
$reservation = $client->reservations->create([
'cenoteId' => 'c3n0t3-1234',
'visitDate' => '2024-07-15',
'visitTime' => '10:00',
'visitors' => [
'adults' => 2,
'children' => 2
],
'guest' => [
'name' => 'John Smith',
'email' => 'john@example.com',
'phone' => '+1-555-123-4567'
]
]);
// Check-in de huésped
$checkedIn = $client->reservations->checkIn('res_1234567890abcdef', [
'actualVisitors' => [
'adults' => 2,
'children' => 2
],
'staff' => [
'name' => 'Maria Rodriguez',
'id' => 'staff_456'
]
]);
?>