Saltar al contenido principal

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ámetroTipoRequeridoDescripciónEjemplo
pageintegerNoNúmero de página (por defecto: 1)?page=1
perPageintegerNoElementos por página (por defecto: 15, máx: 100)?perPage=20
cursorstringNoCursor para paginación basada en cursor?cursor=eyJpZCI6InJlc18xMjM0In0
statusstringNoFiltrar por estado?status=confirmed
cenoteIdstringNoFiltrar por ID de cenote?cenoteId=c3n0t3-1234
guestEmailstringNoFiltrar por email del huésped?guestEmail=guest@example.com
dateFromstringNoFiltrar desde fecha (ISO 8601)?dateFrom=2024-07-01
dateTostringNoFiltrar hasta fecha (ISO 8601)?dateTo=2024-07-31
createdAfterstringNoFiltrar por fecha de creación?createdAfter=2024-01-01
sortBystringNoCampo de ordenamiento?sortBy=visitDate
sortDirectionstringNoDirección de ordenamiento (asc o desc)?sortDirection=desc
expandstringNoRecursos relacionados a incluir?expand=cenote,guest

Valores de Estado

EstadoDescripción
pendingReserva creada, esperando pago
confirmedPago recibido, reserva confirmada
cancelledReserva cancelada
no_showEl huésped no se presentó
completedVisita completada exitosamente
refundedReserva 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

CampoTipoRequeridoDescripción
cenoteIdstringUUID del cenote
visitDatestringFecha de visita (YYYY-MM-DD)
visitTimestringNoHorario preferido (HH:MM)
visitorsobjectConteo de visitantes por tipo
guestobjectInformación del huésped principal
servicesarrayNoServicios adicionales
specialRequestsstringNoSolicitudes especiales o notas
promoCodestringNoCódigo promocional
metadataobjectNoMetadatos 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ámetroTipoRequeridoDescripción
idstringID de reserva o referencia de reserva
expandstringNoRecursos relacionados a incluir

Opciones de Expansión

ValorDescripción
cenoteIncluir información completa del cenote
paymentIncluir información detallada del pago
servicesIncluir detalles completos de servicios
reviewsIncluir 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ónDescripción
addAgregar un nuevo servicio
removeEliminar un servicio existente
updateActualizar 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ónDescripción
guest_requestCancelación iniciada por el huésped
weatherCancelación relacionada con el clima
maintenanceMantenimiento del cenote requerido
capacity_issueProblema de capacidad o disponibilidad
force_majeureCircunstancias 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'
]
]);
?>

Próximos Pasos