Checkout y Pagos
Guía completa para el procesamiento de pagos con Stripe, PayPal, MercadoPago y pagos en sitio.
Vista General
LosCenotes soporta múltiples pasarelas de pago:
| Pasarela | Descripción | Región |
|---|---|---|
| Stripe | Tarjetas de crédito/débito | Global |
| PayPal | Cuentas PayPal | Global |
| MercadoPago | Popular en Latinoamérica | LATAM |
| On-Site | Pago en ubicación | Local |
Flujo de Pago
1. Calcular Precio → /pricing/calculate-complete
2. Validar Reservación → /public/reservations/validate (opcional)
3. Crear Intención de Pago → /checkout/{provider}/create
4. Procesar Pago → Redirigir o Confirmar
5. Recibir Confirmación → Webhook o Callback
Métodos de Pago
GET /payment-methods
Listar todos los métodos de pago disponibles.
curl -X GET "https://service-gateway.loscenotes.com/payment-methods" \
-H "Content-Type: application/json"
Respuesta:
{
"success": true,
"message": "payment_methods.list_retrieved_successfully",
"data": [
{
"id": "pm-stripe",
"provider": "stripe",
"name": {
"es": "Tarjeta de crédito/débito",
"en": "Credit/Debit Card"
},
"description": {
"es": "Paga con Visa, Mastercard, Amex",
"en": "Pay with Visa, Mastercard, Amex"
},
"isActive": true,
"supportedCards": ["visa", "mastercard", "amex"],
"iconUrl": "/icons/stripe.svg",
"processingFee": 0,
"minAmount": 1000,
"maxAmount": 10000000,
"requiresNativeProcessing": true
},
{
"id": "pm-paypal",
"provider": "paypal",
"name": {
"es": "PayPal",
"en": "PayPal"
},
"description": {
"es": "Paga con tu cuenta PayPal",
"en": "Pay with your PayPal account"
},
"isActive": true,
"iconUrl": "/icons/paypal.svg",
"processingFee": 0,
"minAmount": 1000,
"maxAmount": 10000000,
"requiresNativeProcessing": false
},
{
"id": "pm-mercadopago",
"provider": "mercadopago",
"name": {
"es": "MercadoPago",
"en": "MercadoPago"
},
"description": {
"es": "Paga con MercadoPago, OXXO, SPEI",
"en": "Pay with MercadoPago, OXXO, SPEI"
},
"isActive": true,
"iconUrl": "/icons/mercadopago.svg",
"processingFee": 0,
"minAmount": 1000,
"maxAmount": 10000000,
"requiresNativeProcessing": false
},
{
"id": "pm-onsite",
"provider": "on_site",
"name": {
"es": "Pago en sitio",
"en": "Pay on-site"
},
"description": {
"es": "Paga al llegar al cenote (efectivo o tarjeta)",
"en": "Pay when you arrive at the cenote (cash or card)"
},
"isActive": true,
"iconUrl": "/icons/cash.svg",
"processingFee": 0,
"minAmount": 1000,
"maxAmount": 5000000,
"requiresNativeProcessing": false
}
],
"pagination": {
"total": 4,
"perPage": 10,
"currentPage": 1,
"lastPage": 1
}
}
GET /payment-methods/active
Obtener solo métodos de pago activos (recomendado para frontend).
curl -X GET "https://service-gateway.loscenotes.com/payment-methods/active" \
-H "Content-Type: application/json"
Pagos con Stripe
POST /checkout/stripe/create-payment-intent
Crear un PaymentIntent de Stripe para pagos con tarjeta.
curl -X POST "https://service-gateway.loscenotes.com/checkout/stripe/create-payment-intent" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"reservationId": "reservation-uuid",
"amount": 157500,
"currency": "MXN",
"customerEmail": "cliente@email.com",
"metadata": {
"cenoteId": "cenote-uuid",
"visitDate": "2025-03-15"
}
}'
Respuesta:
{
"success": true,
"message": "checkout.payment_intent_created_successfully",
"data": {
"clientSecret": "pi_3MQ...secret_abc123",
"paymentIntentId": "pi_3MQExample",
"amount": 157500,
"currency": "mxn",
"status": "requires_payment_method"
}
}
POST /checkout/stripe/confirm
Confirmar un pago de Stripe después de que el cliente ingresó los datos de tarjeta.
curl -X POST "https://service-gateway.loscenotes.com/checkout/stripe/confirm" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"paymentIntentId": "pi_3MQExample",
"paymentMethodId": "pm_card_visa"
}'
Respuesta:
{
"success": true,
"message": "checkout.payment_confirmed_successfully",
"data": {
"paymentIntentId": "pi_3MQExample",
"status": "succeeded",
"reservationId": "reservation-uuid",
"confirmationCode": "RES-ABC123",
"paidAt": "2025-03-10T15:30:00.000Z"
}
}
Pagos con PayPal
POST /checkout/paypal/create-order
Crear una orden de PayPal para pago.
curl -X POST "https://service-gateway.loscenotes.com/checkout/paypal/create-order" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"reservationId": "reservation-uuid",
"amount": 157500,
"currency": "MXN",
"returnUrl": "https://yourapp.com/payment/success",
"cancelUrl": "https://yourapp.com/payment/cancel"
}'
Respuesta:
{
"success": true,
"message": "checkout.paypal_order_created_successfully",
"data": {
"orderId": "5O190127TN364715T",
"approvalUrl": "https://www.paypal.com/checkoutnow?token=5O190127TN364715T",
"status": "CREATED"
}
}
POST /checkout/paypal/capture
Capturar un pago de PayPal después de que el usuario lo aprobó.
curl -X POST "https://service-gateway.loscenotes.com/checkout/paypal/capture" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"orderId": "5O190127TN364715T"
}'
Respuesta:
{
"success": true,
"message": "checkout.paypal_payment_captured_successfully",
"data": {
"orderId": "5O190127TN364715T",
"status": "COMPLETED",
"reservationId": "reservation-uuid",
"confirmationCode": "RES-ABC123",
"paidAt": "2025-03-10T15:30:00.000Z"
}
}
Pagos con MercadoPago
POST /checkout/mercadopago-native/create-preference
Crear una preferencia de MercadoPago para Checkout Pro.
curl -X POST "https://service-gateway.loscenotes.com/checkout/mercadopago-native/create-preference" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"reservationId": "reservation-uuid",
"items": [
{
"title": "Cenote Dos Ojos - 2 Adultos",
"quantity": 1,
"unitPrice": 1575,
"currency": "MXN"
}
],
"payer": {
"email": "cliente@email.com",
"name": "Juan Pérez"
},
"backUrls": {
"success": "https://yourapp.com/payment/success",
"failure": "https://yourapp.com/payment/failure",
"pending": "https://yourapp.com/payment/pending"
}
}'
Respuesta:
{
"success": true,
"message": "checkout.mercadopago_preference_created_successfully",
"data": {
"preferenceId": "1234567890-abc123-def456",
"checkoutUrl": "https://www.mercadopago.com.mx/checkout/v1/redirect?pref_id=1234567890-abc123-def456",
"initPoint": "https://www.mercadopago.com.mx/checkout/v1/redirect?pref_id=1234567890-abc123-def456"
}
}
Nota: Redirige al usuario a
checkoutUrlpara completar el pago en la página alojada de MercadoPago.
Pagos en Sitio
POST /checkout/on-site
Registrar un pago en sitio (pagar en ubicación).
curl -X POST "https://service-gateway.loscenotes.com/checkout/on-site" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"reservationId": "reservation-uuid",
"paymentMethod": "cash",
"notes": "Customer will pay in cash at arrival"
}'
Respuesta:
{
"success": true,
"message": "checkout.on_site_payment_registered",
"data": {
"reservationId": "reservation-uuid",
"status": "pending_payment",
"confirmationCode": "RES-ABC123",
"paymentDue": "on_arrival"
}
}
Validación de Reservación
POST /public/reservations/validate
Pre-validar una reservación antes de crearla.
curl -X POST "https://service-gateway.loscenotes.com/public/reservations/validate" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_live_your_api_key" \
-d '{
"cenoteId": "cenote-uuid",
"date": "2025-03-15",
"startTime": "09:00",
"endTime": "12:00",
"ageBreakdown": {
"adult": 2,
"child": 1
},
"guestEmail": "cliente@email.com",
"guestName": "Juan Pérez"
}'
Respuesta:
{
"success": true,
"message": "reservation.validation_completed",
"data": {
"isValid": true,
"availability": {
"available": true,
"remainingCapacity": 45
},
"pricing": {
"basePrice": 35000,
"totalVisitors": 3,
"subtotal": 91000,
"discounts": 0,
"total": 91000,
"currency": "MXN"
},
"warnings": [],
"errors": []
}
}
Webhooks
Las confirmaciones de pago también se envían via webhooks. Configura tu URL de webhook en el portal de partners.
Eventos de Webhook
| Evento | Descripción |
|---|---|
payment.completed | Pago exitoso |
payment.failed | Pago falló |
payment.refunded | Pago fue reembolsado |
reservation.confirmed | Reservación confirmada |
reservation.cancelled | Reservación cancelada |
Payload del Webhook
{
"event": "payment.completed",
"timestamp": "2025-03-10T15:30:00.000Z",
"data": {
"reservationId": "reservation-uuid",
"confirmationCode": "RES-ABC123",
"paymentId": "payment-uuid",
"amount": 157500,
"currency": "MXN",
"paymentMethod": "stripe",
"paidAt": "2025-03-10T15:30:00.000Z"
}
}
Manejo de Errores
Errores de Pago
| Error | Descripción |
|---|---|
card_declined | Tarjeta rechazada |
insufficient_funds | Fondos insuficientes |
expired_card | Tarjeta expirada |
invalid_cvc | Código de seguridad inválido |
processing_error | Error de procesamiento |
Mejores Prácticas
try {
const result = await createPaymentIntent(data);
// Handle success
} catch (error) {
if (error.code === 'card_declined') {
showError('Tu tarjeta fue rechazada. Intenta con otra.');
} else if (error.code === 'insufficient_funds') {
showError('Fondos insuficientes en tu tarjeta.');
} else {
showError('Error al procesar el pago. Intenta de nuevo.');
}
}
Moneda
Todos los precios en la API se devuelven en CENTAVOS.
| Monto | Centavos | Mostrar |
|---|---|---|
| $350.00 MXN | 35000 | (35000 / 100).toFixed(2) |
| $1,575.00 MXN | 157500 | (157500 / 100).toFixed(2) |
| $15.00 USD | 1500 | (1500 / 100).toFixed(2) |
// Convertir centavos a formato de visualización
const formatPrice = (cents, currency = 'MXN') => {
const amount = cents / 100;
return new Intl.NumberFormat('es-MX', {
style: 'currency',
currency: currency
}).format(amount);
};
console.log(formatPrice(157500)); // "$1,575.00"