Skip to main content

Checkout & Payments

Complete guide for payment processing with Stripe, PayPal, MercadoPago, and on-site payments.


Overview

LosCenotes supports multiple payment gateways:

GatewayDescriptionRegion
StripeCredit/Debit cardsGlobal
PayPalPayPal accountsGlobal
MercadoPagoPopular in Latin AmericaLATAM
On-SitePay at locationLocal

Payment Flow

1. Calculate Price → /pricing/calculate-complete
2. Validate Reservation → /public/reservations/validate (optional)
3. Create Payment Intent → /checkout/{provider}/create
4. Process Payment → Redirect or Confirm
5. Receive Confirmation → Webhook or Callback

Payment Methods

GET /payment-methods

List all available payment methods.

curl -X GET "https://service-gateway.loscenotes.com/payment-methods" \
-H "Content-Type: application/json"

Response:

{
"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

Get only active payment methods (recommended for frontend).

curl -X GET "https://service-gateway.loscenotes.com/payment-methods/active" \
-H "Content-Type: application/json"

Stripe Payments

POST /checkout/stripe/create-payment-intent

Create a Stripe Payment Intent for card payments.

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"
}
}'

Response:

{
"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

Confirm a Stripe payment after the client has entered card details.

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"
}'

Response:

{
"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"
}
}

PayPal Payments

POST /checkout/paypal/create-order

Create a PayPal order for payment.

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"
}'

Response:

{
"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

Capture a PayPal payment after the user has approved it.

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"
}'

Response:

{
"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"
}
}

MercadoPago Payments

POST /checkout/mercadopago-native/create-preference

Create a MercadoPago preference for 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"
}
}'

Response:

{
"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"
}
}

Note: Redirect the user to checkoutUrl to complete payment on MercadoPago's hosted page.


On-Site Payments

POST /checkout/on-site

Register an on-site payment (pay at location).

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"
}'

Response:

{
"success": true,
"message": "checkout.on_site_payment_registered",
"data": {
"reservationId": "reservation-uuid",
"status": "pending_payment",
"confirmationCode": "RES-ABC123",
"paymentDue": "on_arrival"
}
}

Reservation Validation

POST /public/reservations/validate

Pre-validate a reservation before creating it.

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"
}'

Response:

{
"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

Payment confirmations are also sent via webhooks. Configure your webhook URL in the partner portal.

Webhook Events

EventDescription
payment.completedPayment was successful
payment.failedPayment failed
payment.refundedPayment was refunded
reservation.confirmedReservation confirmed
reservation.cancelledReservation cancelled

Webhook Payload

{
"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"
}
}

Error Handling

Payment Errors

ErrorDescription
card_declinedCard was declined
insufficient_fundsInsufficient funds
expired_cardCard has expired
invalid_cvcInvalid security code
processing_errorPayment processing error

Best Practice

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.');
}
}

Currency

All prices in the API are returned in CENTS (centavos).

AmountCentsDisplay
$350.00 MXN35000(35000 / 100).toFixed(2)
$1,575.00 MXN157500(157500 / 100).toFixed(2)
$15.00 USD1500(1500 / 100).toFixed(2)
// Convert cents to display
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"