Embedded Checkout
El Embedded Checkout es un widget que puedes integrar directamente en tu sitio web, permitiendo a tus clientes crear su propia solicitud de pago. El widget maneja automáticamente la selección de país, validación de datos y redirige al cliente al proceso de checkout.

Requisitos Previos
Sección titulada «Requisitos Previos»Antes de integrar el Embedded Checkout, necesitas:
1. Crear una Clave API
Sección titulada «1. Crear una Clave API»Debes crear una clave API desde el dashboard de Aloha Pay. Esta clave se usará para autenticar las solicitudes del widget.
2. Configurar Allowed Origins
Sección titulada «2. Configurar Allowed Origins»Los Allowed Origins son las URLs de los sitios web donde utilizarás el Embedded Checkout. Por ejemplo:
https://tudominio.comhttps://www.tudominio.comhttp://localhost:3000(para desarrollo)
Puedes configurar los Allowed Origins al crear o editar tu clave API en el dashboard de Aloha Pay.
Instalación
Sección titulada «Instalación»Incluye el script directamente desde nuestro CDN:
<script src="https://cdn.alohapay.co/v2/aloha-pay.umd.js"></script>Integración por Framework
Sección titulada «Integración por Framework»<!DOCTYPE html><html><head> <title>Checkout - Mi Tienda</title></head><body> <div id="aloha-checkout"></div>
<script src="https://cdn.alohapay.co/v2/aloha-pay.umd.js"></script> <script> const checkout = AlohaPay.create({ // Requeridos apiKey: 'pay_xxxxx_live_xxxxxxxxxxxxx', container: '#aloha-checkout', amount: 60000,
// Opcionales locale: 'es', description: 'Compra en Mi Tienda', defaultCountry: 'CL', useSandbox: false, hideAmount: true,
// Estilos personalizados styles: { headerBackground: 'linear-gradient(135deg, #846ffb 0%, #6b5fcd 100%)', buttonColor: '#846ffb', maxWidth: '480px' },
// Datos pre-llenados del cliente (opcional) customer: { firstName: 'Juan', lastName: 'Pérez', email: 'juan@email.com', phone: '+56912345678' },
// Callbacks onReady: () => { console.log('Widget listo'); }, onError: (error) => { console.error('Error:', error); }, onPaymentLinkCreated: (checkoutUrl) => { console.log('Link de pago creado:', checkoutUrl); }, onPaymentComplete: () => { console.log('¡Pago completado!'); // Aquí puedes redirigir al usuario o mostrar confirmación } }); </script></body></html>import { useEffect, useRef, useState } from 'react';
// Declaración de tipos para AlohaPaydeclare global { interface Window { AlohaPay: { create: (config: AlohaPayConfig) => AlohaPayInstance; }; }}
interface AlohaPayConfig { apiKey: string; container: string; amount: number; locale?: 'en' | 'es' | 'pt'; description?: string; defaultCountry?: string; useSandbox?: boolean; hideAmount?: boolean; styles?: { headerBackground?: string; amountColor?: string; buttonColor?: string; buttonTextColor?: string; linkColor?: string; maxWidth?: string; }; customer?: { firstName?: string; lastName?: string; email?: string; phone?: string; }; onReady?: () => void; onError?: (error: Error) => void; onPaymentLinkCreated?: (checkoutUrl: string) => void; onPaymentComplete?: () => void;}
interface AlohaPayInstance { destroy?: () => void;}
interface EmbeddedCheckoutProps { apiKey: string; amount: number; description?: string; locale?: 'en' | 'es' | 'pt'; defaultCountry?: string; useSandbox?: boolean; onPaymentComplete?: () => void; onError?: (error: Error) => void;}
export function EmbeddedCheckout({ apiKey, amount, description = 'Pago', locale = 'es', defaultCountry, useSandbox = false, onPaymentComplete, onError}: EmbeddedCheckoutProps) { const containerRef = useRef<HTMLDivElement>(null); const [isLoaded, setIsLoaded] = useState(false);
// Cargar el script de Aloha Pay useEffect(() => { if (window.AlohaPay) { setIsLoaded(true); return; }
const script = document.createElement('script'); script.src = 'https://cdn.alohapay.co/v2/aloha-pay.umd.js'; script.async = true; script.onload = () => setIsLoaded(true); script.onerror = () => onError?.(new Error('Error al cargar Aloha Pay')); document.body.appendChild(script);
return () => { document.body.removeChild(script); }; }, [onError]);
// Inicializar el widget useEffect(() => { if (!isLoaded || !containerRef.current) return;
const checkout = window.AlohaPay.create({ apiKey, container: '#aloha-checkout-container', amount, description, locale, defaultCountry, useSandbox, onReady: () => console.log('Aloha Pay listo'), onError: (error) => onError?.(error), onPaymentComplete: () => onPaymentComplete?.() });
return () => { checkout.destroy?.(); }; }, [isLoaded, apiKey, amount, description, locale, defaultCountry, useSandbox, onPaymentComplete, onError]);
return <div id="aloha-checkout-container" ref={containerRef} />;}
// Uso del componentefunction CheckoutPage() { const handlePaymentComplete = () => { alert('¡Pago exitoso!'); // Redirigir o actualizar UI };
return ( <EmbeddedCheckout apiKey="pay_xxxxx_live_xxxxxxxxxxxxx" amount={60000} description="Compra en Mi Tienda" locale="es" defaultCountry="CL" onPaymentComplete={handlePaymentComplete} onError={(error) => console.error(error)} /> );}<template> <div id="aloha-checkout-container" ref="checkoutContainer"></div></template>
<script setup lang="ts">import { ref, onMounted, onUnmounted, watch } from 'vue';
interface Props { apiKey: string; amount: number; description?: string; locale?: 'en' | 'es' | 'pt'; defaultCountry?: string; useSandbox?: boolean; hideAmount?: boolean;}
const props = withDefaults(defineProps<Props>(), { description: 'Pago', locale: 'es', useSandbox: false});
const emit = defineEmits<{ ready: []; error: [error: Error]; paymentLinkCreated: [checkoutUrl: string]; paymentComplete: [];}>();
const checkoutContainer = ref<HTMLDivElement>();let checkoutInstance: any = null;let scriptLoaded = false;
const loadScript = (): Promise<void> => { return new Promise((resolve, reject) => { if ((window as any).AlohaPay) { resolve(); return; }
const script = document.createElement('script'); script.src = 'https://cdn.alohapay.co/v2/aloha-pay.umd.js'; script.async = true; script.onload = () => resolve(); script.onerror = () => reject(new Error('Error al cargar Aloha Pay')); document.body.appendChild(script); });};
const initCheckout = async () => { try { if (!scriptLoaded) { await loadScript(); scriptLoaded = true; }
if (checkoutInstance?.destroy) { checkoutInstance.destroy(); }
checkoutInstance = (window as any).AlohaPay.create({ apiKey: props.apiKey, container: '#aloha-checkout-container', amount: props.amount, description: props.description, locale: props.locale, defaultCountry: props.defaultCountry, useSandbox: props.useSandbox, onReady: () => emit('ready'), onError: (error: Error) => emit('error', error), onPaymentLinkCreated: (url: string) => emit('paymentLinkCreated', url), onPaymentComplete: () => emit('paymentComplete') }); } catch (error) { emit('error', error as Error); }};
onMounted(() => { initCheckout();});
onUnmounted(() => { checkoutInstance?.destroy?.();});
// Re-inicializar si cambian las props importanteswatch(() => [props.amount, props.apiKey], () => { initCheckout();});</script>Uso del componente:
<template> <EmbeddedCheckout api-key="pay_xxxxx_live_xxxxxxxxxxxxx" :amount="60000" description="Compra en Mi Tienda" locale="es" default-country="CL" @payment-complete="handlePaymentComplete" @error="handleError" /></template>
<script setup lang="ts">import EmbeddedCheckout from './EmbeddedCheckout.vue';
const handlePaymentComplete = () => { alert('¡Pago exitoso!');};
const handleError = (error: Error) => { console.error('Error en el checkout:', error);};</script>Configuración
Sección titulada «Configuración»Propiedades Requeridas
Sección titulada «Propiedades Requeridas»| Propiedad | Tipo | Descripción |
|---|---|---|
apiKey | string | Tu clave API de Aloha Pay |
container | string | Selector CSS del contenedor donde se renderiza el widget |
amount | number | Monto a cobrar en la moneda de tu billetera |
Propiedades Opcionales
Sección titulada «Propiedades Opcionales»| Propiedad | Tipo | Default | Descripción |
|---|---|---|---|
locale | 'en' | 'es' | 'pt' | 'en' | Idioma del widget |
description | string | 'Payment' | Descripción del pago |
defaultCountry | string | undefined | Código de país pre-seleccionado (ej: 'BR', 'MX', 'CL') |
useSandbox | boolean | false | Usar ambiente de pruebas |
hideAmount | boolean | false | Oculta el monto en la parte superior del widget |
customer | CustomerData | undefined | Datos pre-llenados del cliente |
styles | CheckoutStyles | undefined | Estilos personalizados |
CustomerData
Sección titulada «CustomerData»| Propiedad | Tipo | Descripción |
|---|---|---|
firstName | string | Nombre del cliente |
lastName | string | Apellido del cliente |
email | string | Email del cliente |
phone | string | Teléfono del cliente (con código de país) |
CheckoutStyles
Sección titulada «CheckoutStyles»| Propiedad | Tipo | Default | Descripción |
|---|---|---|---|
headerBackground | string | linear-gradient(135deg, #846ffb 0%, #6b5fcd 100%) | Fondo del header |
amountColor | string | #ffffff | Color del texto del monto |
buttonColor | string | #846ffb | Color de fondo del botón |
buttonTextColor | string | #ffffff | Color del texto del botón |
linkColor | string | #846ffb | Color de los enlaces |
maxWidth | string | 480px | Ancho máximo del widget |
Eventos (Callbacks)
Sección titulada «Eventos (Callbacks)»El widget proporciona varios callbacks para que puedas reaccionar a los diferentes estados del proceso de pago:
| Evento | Parámetros | Descripción |
|---|---|---|
onReady | - | Se ejecuta cuando el widget está completamente cargado y listo para usar |
onError | error: Error | Se ejecuta cuando ocurre un error (fallos de red, validación, etc.) |
onPaymentLinkCreated | checkoutUrl: string | Se ejecuta cuando se genera el link de pago y el usuario es redirigido |
onPaymentComplete | - | Se ejecuta cuando el pago se completa exitosamente |
Ejemplo de manejo de eventos
Sección titulada «Ejemplo de manejo de eventos»AlohaPay.create({ apiKey: 'pay_xxxxx_live_xxxxxxxxxxxxx', container: '#checkout', amount: 50000,
onReady: () => { // Ocultar spinner de carga document.getElementById('loading').style.display = 'none'; },
onError: (error) => { // Mostrar mensaje de error al usuario alert(`Error: ${error.message}`); // Enviar a tu sistema de monitoreo logError(error); },
onPaymentLinkCreated: (checkoutUrl) => { // El checkout se abrió en una nueva pestaña // Puedes guardar la URL o mostrar instrucciones console.log('Continúa el pago en:', checkoutUrl); },
onPaymentComplete: () => { // Mostrar confirmación showSuccessMessage(); // Redirigir a página de confirmación window.location.href = '/orden-confirmada'; }});Flujo del Widget
Sección titulada «Flujo del Widget»┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ │ │ │ │ ││ Formulario │────▶│ Esperando │────▶│ Completado ││ │ │ Pago │ │ │└─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ ▼ ▼ Validación Abre checkout de datos en nueva pestaña + polling cada 3s- Formulario: El cliente selecciona país e ingresa sus datos
- Esperando: Se abre el checkout en nueva pestaña, el widget hace polling para detectar el pago
- Completado: Se muestra confirmación cuando el pago es exitoso
Verificación con Webhooks
Sección titulada «Verificación con Webhooks»El callback onPaymentComplete es útil para mejorar la experiencia del usuario, pero no es seguro para confirmar transacciones porque:
- Puede ser manipulado por usuarios maliciosos
- El usuario podría cerrar el navegador antes de que se ejecute
- Problemas de red podrían impedir que el evento llegue
Implementación recomendada
Sección titulada «Implementación recomendada»- En el frontend: Usa
onPaymentCompletepara mostrar feedback inmediato al usuario - En el backend: Configura webhooks para recibir notificaciones seguras de pagos completados
- Verificación: Siempre verifica la firma del webhook antes de procesar
Ejemplo de flujo seguro
Sección titulada «Ejemplo de flujo seguro»// Frontend - Solo para UXonPaymentComplete: () => { // Mostrar mensaje provisional showMessage('Verificando pago...');
// Consultar tu backend para confirmar checkPaymentStatus(orderId).then(status => { if (status === 'confirmed') { redirectToConfirmation(); } });}// Backend - Webhook handler (Node.js/Express)app.post('/webhooks/aloha-pay', (req, res) => { const signature = req.headers['x-aloha-signature'];
// Verificar firma if (!verifySignature(req.body, signature, webhookSecret)) { return res.status(401).send('Invalid signature'); }
const event = req.body;
if (event.type === 'payment.completed') { // Actualizar orden en tu base de datos updateOrderStatus(event.data.orderId, 'paid'); }
res.status(200).send('OK');});Países Soportados
Sección titulada «Países Soportados»| Código | País |
|---|---|
AR | Argentina |
BR | Brasil |
CL | Chile |
CO | Colombia |
MX | México |
Ambientes
Sección titulada «Ambientes»| Ambiente | API URL | Uso |
|---|---|---|
| Producción | https://api.alohapay.co/api/external/v1 | Transacciones reales |
| Sandbox | https://api-dev.alohapay.co/api/external/v1 | Pruebas y desarrollo |
Para usar el ambiente de pruebas, configura useSandbox: true en la inicialización del widget.
Solución de Problemas
Sección titulada «Solución de Problemas»El widget no carga
Sección titulada «El widget no carga»- Verifica que el script esté correctamente incluido
- Revisa la consola del navegador por errores
- Confirma que el contenedor existe en el DOM antes de inicializar
Error de CORS / Origin no permitido
Sección titulada «Error de CORS / Origin no permitido»- Verifica que hayas configurado los Allowed Origins en tu clave API
- Asegúrate de incluir el protocolo completo (
https://ohttp://) - Para desarrollo local, agrega
http://localhost:PUERTO
El pago no se detecta como completado
Sección titulada «El pago no se detecta como completado»- Verifica que los webhooks estén correctamente configurados
- Revisa los logs de tu servidor para errores
- Confirma que tu servidor responde con status 200 a los webhooks