Hotelpay SDK
El SDK de Hotelpay proporciona una forma sencilla de integrar pagos en tu aplicación web. Soporta dos modos de integración: Overlay e Iframe.
Instalación
Agrega el script del SDK a tu página:
<script src="https://js.hotelpay.net/v2/sdk/hotelpay.umd.js"></script>
Referencia API
Hotelpay: {
Checkout: {
// Configuración General
setApiKey: (key: string) => Promise<void>;
setCurrency: (currency: "MXN" | "USD") => void;
setTotal: (total: number) => void;
setDetails: (data: Details) => void;
setMode: (mode: "testing" | "production") => void;
setLanguage: (lang: "es" | "en") => void;
setAddress: (address: Address) => void;
// Modo Overlay
showOverlay: () => void;
onSuccess: (callback: () => void) => void;
onCancel: (callback: () => void) => void;
onFail: (callback: (error?: any) => void) => void;
// Modo Iframe
renderIframe: (selector: string) => Promise<void>;
on: (event: string, callback: Function) => void;
processPayment: () => Promise<void>;
// Personalización
setCSS: (css: string) => void;
}
}
Ambientes
Testing
Ambiente para pruebas y desarrollo. Usa tarjetas de prueba para simular transacciones sin realizar cargos reales. Este ambiente es crucial para verificar la integración y el flujo de pago antes de ir a producción.
Hotelpay.Checkout.setMode("testing");
Production
Ambiente de producción para transacciones reales. Asegúrate de haber probado exhaustivamente en el ambiente de testing antes de cambiar a producción, ya que aquí se realizarán cargos reales a las tarjetas.
Hotelpay.Checkout.setMode("production");
Configuración Básica
setApiKey
Establece la clave API para autenticar las solicitudes. Esta clave es única para cada comercio y ambiente.
Hotelpay.Checkout.setApiKey("tu_api_key");
setCurrency
Define la moneda para las transacciones. Actualmente se soportan pesos mexicanos (MXN) y dólares americanos (USD).
Hotelpay.Checkout.setCurrency("MXN"); // o "USD"
setTotal
Establece el monto total de la transacción. Es importante notar que solo se permiten hasta 2 decimales.
// El monto debe tener máximo 2 decimales
Hotelpay.Checkout.setTotal(444.44);
setLanguage
Define el idioma de la interfaz. Actualmente se soportan español (es) e inglés (en).
Hotelpay.Checkout.setLanguage("es"); // o "en"
setDetails
Configura los detalles de la reservación. Este método requiere información específica sobre la reserva, los items a cobrar y el cliente.
Hotelpay.Checkout.setDetails({
// ID interno opcional para referencia del comercio
referenceId: "reserva-123",
// Datos de la reserva (requerido)
reserve_data: {
booking_number: "00001", // Número de reserva
checkin: "2024-12-01", // Fecha de entrada
checkout: "2024-12-31", // Fecha de salida
guests_adults: 2, // Número de adultos
guests_children: 1 // Número de niños
},
// Items a cobrar (requerido)
// Cada item debe especificar descripción, precio y cantidad
items: [
{
description: "Habitación doble vista al mar",
price: 56.79,
quantity: 1
}
],
// Información del cliente (requerido)
customer_info: {
first_name: "Juan",
last_name: "Pérez",
phone: "5512345678",
email: "juan@ejemplo.com"
}
});
setAddress
Establece la dirección de facturación del cliente. Esta información es importante para la validación de la tarjeta.
Hotelpay.Checkout.setAddress({
address: "Calle Principal 123",
city: "Ciudad de México",
state: "CDMX",
country: "México",
country_code: "MX", // Código ISO del país
zip: "01234"
});
processPayment
Este método inicia el proceso de pago con la información proporcionada. Es asíncrono y debe ser llamado con await o manejado como una promesa.
- El formulario de tarjeta esté completo y válido (
complete-form-cardconis_valid: true) - Hayas establecido toda la información requerida (
setDetails,setAddress, etc.)
try {
// Iniciar el proceso de pago
await Hotelpay.Checkout.processPayment();
// El pago se procesará y se emitirán los eventos correspondientes
// (paymentCompleted o paymentError)
} catch (error) {
// Manejar cualquier error inesperado
console.error('Error al procesar el pago:', error);
}
Modo Overlay
El modo overlay muestra el formulario de pago en una ventana modal sobre tu sitio. Es la forma más sencilla de integrar el SDK.
Implementación Básica
// Configurar callbacks para manejar los diferentes estados del pago
Hotelpay.Checkout.onSuccess(() => {
// Se ejecuta cuando el pago es exitoso
console.log("Pago exitoso");
});
Hotelpay.Checkout.onFail((error) => {
// Se ejecuta cuando hay un error en el pago
// El parámetro error contiene detalles sobre el problema
console.log("Error en el pago:", error);
});
Hotelpay.Checkout.onCancel(() => {
// Se ejecuta cuando el usuario cancela el pago
console.log("Pago cancelado");
});
// Mostrar el overlay de pago
Hotelpay.Checkout.showOverlay();
Modo Iframe
El modo iframe integra el formulario de pago directamente en tu página. Este modo ofrece mayor flexibilidad en la integración y personalización.
Implementación Básica (Iframe)
<!DOCTYPE html>
<html>
<head>
<title>Checkout con Iframe</title>
<script src="https://cdn.hotelpay.com/sdk/v2/sdk.js"></script>
<style>
#iframe-container {
width: 100%;
max-width: 600px;
margin: 0 auto;
}
#payment-button {
display: block;
width: 100%;
padding: 12px;
background: #4F46E5;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
margin-top: 20px;
}
#payment-button:disabled {
background: #9CA3AF;
cursor: not-allowed;
}
</style>
</head>
<body>
<div id="iframe-container">
<div id="payment-form"></div>
<button id="payment-button" disabled>Pagar $100.00 MXN</button>
</div>
<script>
const { Checkout } = Hotelpay;
const payButton = document.getElementById('payment-button');
// Configuración inicial
Checkout.setApiKey('tu_api_key');
Checkout.setMode('testing');
Checkout.setLanguage('es');
Checkout.setCurrency('MXN');
Checkout.setTotal(100);
// Renderizar iframe
Checkout.renderIframe('#payment-form');
// Escuchar evento de formulario completo
Checkout.on('complete-form-card', (data) => {
payButton.disabled = !data.is_valid;
});
// Escuchar inicio de transacción
Checkout.on('transaction-start', () => {
payButton.disabled = true;
payButton.textContent = 'Procesando...';
});
// Escuchar transacción completada
Checkout.on('transaction-completed', (data) => {
payButton.textContent = '¡Pago Exitoso!';
console.log('Transacción completada:', data);
});
// Manejar clic en botón de pago
payButton.addEventListener('click', async () => {
try {
await Checkout.processPayment();
} catch (error) {
console.error('Error al procesar el pago:', error);
payButton.disabled = false;
payButton.textContent = 'Reintentar Pago';
}
});
</script>
</body>
</html>
Este ejemplo muestra:
- Configuración básica del SDK
- Renderizado del iframe de pago
- Manejo del estado del botón basado en la validación del formulario
- Procesamiento de pago al hacer clic en el botón
- Actualización de la UI durante el proceso de pago
Eventos Disponibles
El SDK proporciona varios eventos que puedes escuchar para controlar el flujo de pago:
complete-form-card
Se ejecuta cuando cambia el estado de validación del formulario de tarjeta.
Hotelpay.Checkout.on("complete-form-card", (data) => {
// data.is_valid será true cuando:
// - El número de tarjeta sea válido (pasa validación Luhn)
// - La fecha de expiración sea válida y futura
// - El CVV tenga la longitud correcta (3-4 dígitos)
// - El nombre del tarjetahabiente esté completo
if (data.is_valid) {
// Formulario válido
}
});
transaction-start
Se ejecuta cuando inicia el proceso de pago.
Hotelpay.Checkout.on("transaction-start", () => {
// Buen momento para mostrar un indicador de carga
});
toggle-split-payment
Se ejecuta cuando se activa o desactiva el pago dividido.
Hotelpay.Checkout.on("toggle-split-payment", (data) => {
// data.enabled indica si el pago dividido está activo
});
require-installments
Se ejecuta cuando la tarjeta es elegible para meses sin intereses.
Hotelpay.Checkout.on("require-installments", (data) => {
// data.supported_installments contiene los plazos disponibles
// Ejemplo: [{ months: 3, minimum: 1000 }, { months: 6, minimum: 2000 }]
});
paymentCompleted
Se ejecuta cuando el pago se completa exitosamente.
Hotelpay.Checkout.on("paymentCompleted", () => {
// Pago exitoso
});
paymentError
Se ejecuta cuando ocurre un error durante el pago.
Hotelpay.Checkout.on("paymentError", (error) => {
// error contiene detalles sobre el problema
// error.message puede contener un mensaje en español o inglés
// según el idioma configurado
});
Eventos
El SDK emite varios eventos que puedes escuchar para manejar diferentes estados del proceso de pago:
complete-form-card
Emitido cuando se completa el formulario de tarjeta. Recibe un objeto con la propiedad is_valid que indica si los datos son válidos.
Checkout.on('complete-form-card', (data) => {
if (data.is_valid) {
// Habilitar botón de pago
}
});
transaction-start
Emitido cuando inicia el proceso de transacción.
Checkout.on('transaction-start', () => {
// Deshabilitar botón de pago y mostrar estado de procesamiento
});
toggle-split-payment
Emitido cuando se activa o desactiva el pago dividido. Recibe un objeto con la propiedad enabled que indica si está activado.
Checkout.on('toggle-split-payment', (data) => {
console.log('Split payment enabled:', data.enabled);
});
require-installments
Emitido cuando se requiere seleccionar meses sin intereses.
Checkout.on('require-installments', (data) => {
// Mostrar selector de meses sin intereses
});
3ds-start
Emitido cuando se requiere autenticación 3D Secure para una transacción.
Checkout.on('3ds-start', (data) => {
// Manejar inicio de autenticación 3DS
// Se mostrará el desafío 3DS al usuario
});
3ds-end
Emitido cuando finaliza el proceso de autenticación 3D Secure.
Checkout.on('3ds-end', (data) => {
// Manejar finalización de autenticación 3DS
// La transacción continuará su proceso normal
});
adding-card-start
Emitido cuando comienza el proceso de agregar una tarjeta.
Checkout.on('adding-card-start', () => {
// Mostrar indicador de carga
// Deshabilitar botones de interacción
});
adding-card-completed
Emitido cuando se completa el proceso de agregar una tarjeta.
Checkout.on('adding-card-completed', (data) => {
// La tarjeta se agregó exitosamente
// Habilitar siguiente paso del proceso
});
transaction-completed
Emitido cuando una transacción se completa exitosamente.
Checkout.on('transaction-completed', (data) => {
// La transacción fue exitosa
// data contiene información de la transacción
});
transaction-failed
Emitido cuando una transacción falla por cualquier motivo.
Checkout.on('transaction-failed', (error) => {
// La transacción falló
// error contiene detalles del error
});
Personalización
setCSS(css: string)
Permite personalizar los estilos del iframe de pago. El CSS se aplicará solo dentro del iframe.
// Ejemplo de personalización de estilos
Checkout.setCSS(`
.card-field-wrapper {
margin-bottom: 20px;
}
.card-field-error {
color: #dc2626;
}
.amount-field-error {
color: #dc2626;
}
.installments-field-error {
color: #dc2626;
}
.remove-arrows::-webkit-outer-spin-button,
.remove-arrows::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.remove-arrows {
-moz-appearance: textfield;
}
`);
Nota: Los estilos solo se aplicarán cuando se use el modo iframe. En modo overlay se mantienen los estilos por defecto.
Flujo de Meses Sin Intereses (MSI)
El SDK soporta pagos a meses sin intereses (MSI) cuando la tarjeta y el comercio lo permiten. El flujo es el siguiente:
- El usuario ingresa los datos de la tarjeta
- Cuando el formulario está completo y válido, se habilita el botón de pago
- Al hacer clic en el botón de pago, se inicia
processPayment() - Si la tarjeta soporta MSI, el SDK emite el evento
require-installmentscon los plazos disponibles - El iframe se ajusta automáticamente para mostrar el selector de plazos
- El usuario selecciona un plazo y confirma
- La transacción continúa su proceso normal
Ejemplo de implementación de MSI
const { Checkout } = Hotelpay;
const payButton = document.getElementById('payment-button');
// Escuchar validación del formulario
Checkout.on('complete-form-card', (data) => {
payButton.disabled = !data.is_valid;
});
// Escuchar cuando se requiere selección de MSI
Checkout.on('require-installments', (data) => {
console.log('Plazos disponibles:', data.supported_installments);
// El SDK muestra automáticamente el selector de plazos
// No se requiere acción adicional
});
// Escuchar inicio de transacción
Checkout.on('transaction-start', () => {
payButton.disabled = true;
payButton.textContent = 'Procesando...';
});
// Escuchar transacción completada
Checkout.on('transaction-completed', (data) => {
payButton.textContent = '¡Pago Exitoso!';
console.log('Transacción completada:', data);
});
// Manejar clic en botón de pago
payButton.addEventListener('click', async () => {
try {
await Checkout.processPayment();
} catch (error) {
console.error('Error al procesar el pago:', error);
payButton.disabled = false;
payButton.textContent = 'Reintentar Pago';
}
});
El evento require-installments proporciona un objeto data con la siguiente estructura:
{
supported_installments: Array<{
months: number; // Número de meses (ej: 3, 6, 12, etc)
minimum: number; // Monto mínimo requerido para este plazo
}>
}
Nota: El selector de plazos solo se muestra si la tarjeta y el comercio soportan MSI y el monto de la transacción cumple con el mínimo requerido.
Flujo de Pago Combinado
El SDK permite realizar pagos utilizando dos tarjetas diferentes cuando el comercio tiene habilitada esta funcionalidad. El flujo es el siguiente:
- Si el comercio soporta pago combinado y el monto es mayor al mínimo requerido, se muestra un toggle dentro del iframe
- Al activar el toggle:
- Se habilita la captura de una segunda tarjeta
- Se muestra un selector de montos para distribuir el pago entre ambas tarjetas
- Se agrega una comisión por pago combinado (si está configurada)
- El usuario puede:
- Ingresar los datos de ambas tarjetas
- Ajustar los montos a pagar con cada tarjeta
- El total debe coincidir con el monto de la transacción más la comisión
- El flujo de MSI aplica independientemente para cada tarjeta:
- Cada tarjeta puede tener sus propios plazos disponibles
- El usuario puede seleccionar plazos diferentes para cada tarjeta
Ejemplo de implementación de pago combinado
const { Checkout } = Hotelpay;
const payButton = document.getElementById('payment-button');
// Escuchar cambios en el toggle de pago combinado
Checkout.on('toggle-split-payment', (data) => {
console.log('Pago combinado activado:', data.enabled);
// El SDK maneja automáticamente la UI para pago combinado
});
// Escuchar validación del formulario
Checkout.on('complete-form-card', (data) => {
payButton.disabled = !data.is_valid;
});
// Escuchar cuando se requiere selección de MSI (puede ocurrir para ambas tarjetas)
Checkout.on('require-installments', (data) => {
console.log('Plazos disponibles:', data.supported_installments);
// El SDK muestra automáticamente el selector de plazos
});
// Escuchar inicio de transacción
Checkout.on('transaction-start', () => {
payButton.disabled = true;
payButton.textContent = 'Procesando...';
});
// Escuchar transacción completada
Checkout.on('transaction-completed', (data) => {
payButton.textContent = '¡Pago Exitoso!';
console.log('Transacción completada:', data);
});
// Manejar clic en botón de pago
payButton.addEventListener('click', async () => {
try {
await Checkout.processPayment();
} catch (error) {
console.error('Error al procesar el pago:', error);
payButton.disabled = false;
payButton.textContent = 'Reintentar Pago';
}
});
El evento toggle-split-payment proporciona un objeto data con la siguiente estructura:
{
enabled: boolean; // true cuando se activa el pago combinado
}
Nota: El pago combinado solo estará disponible si:
- El comercio tiene habilitada la funcionalidad
- El monto de la transacción es mayor al mínimo requerido
- La comisión por pago combinado está configurada (opcional)
Integración con SweetAlert2
El SDK no incluye una interfaz visual para mensajes y alertas, pero se puede integrar fácilmente con librerías como SweetAlert2 para mejorar la experiencia del usuario.
Instalación de SweetAlert2
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
Ejemplo de Implementación
// Configuración de mensajes por idioma
const messages = {
es: {
processing: "Procesando...",
pleaseWait: "Por favor, espere mientras procesamos su pago.",
cardVerificationFailed: "La verificación de la tarjeta ha fallado. Intenta con otra tarjeta.",
paymentFailed: "No pudimos procesar el pago",
paymentSuccess: "Pago completado exitosamente"
},
en: {
processing: "Processing...",
pleaseWait: "Please wait while we process your payment.",
cardVerificationFailed: "Card verification failed. Please try another card.",
paymentFailed: "We couldn't process the payment",
paymentSuccess: "Payment completed successfully"
}
};
// Función para mostrar el loader
const showProcessingModal = (text) => {
Swal.fire({
title: messages[currentLanguage].processing,
html: `<p>${text}</p>`,
showConfirmButton: false,
allowOutsideClick: false
});
};
// Función para mostrar error
const showErrorModal = (text) => {
Swal.fire({
icon: 'error',
title: messages[currentLanguage].paymentFailed,
html: `<p>${text}</p>`,
showConfirmButton: true
});
};
// Implementación con el SDK
Hotelpay.Checkout.on("transaction-start", () => {
showProcessingModal(messages[currentLanguage].pleaseWait);
});
Hotelpay.Checkout.on("paymentCompleted", () => {
Swal.fire({
icon: 'success',
title: messages[currentLanguage].paymentSuccess
});
});
Hotelpay.Checkout.on("paymentError", (error) => {
showErrorModal(error.message[currentLanguage]);
});
Este ejemplo muestra cómo integrar SweetAlert2 para:
- Mostrar un loader durante el procesamiento
- Mostrar mensajes de éxito
- Mostrar mensajes de error
- Manejar múltiples idiomas
La integración con SweetAlert2 mejora significativamente la experiencia del usuario al proporcionar retroalimentación visual clara durante todo el proceso de pago.