Integración por Iframe
Guía paso a paso para integrar la Hosted Payment Page en su sitio web mediante el iframe.
Resumen del flujo: su backend crea una sesión segura (autenticada vía OAuth 2.0) → recibe un
sessionToken→ su frontend carga el SDK y monta el iframe con ese token → el cliente paga → usted recibe el resultado vía callback o redirección → su backend confirma la transacción.
Requisitos Previos
Antes de comenzar, necesita las credenciales proporcionadas por Inyo:
| Credencial | Descripción |
|---|---|
OAUTH_CLIENT_ID | Identificador de su tenant (cliente). |
OAUTH_CLIENT_SECRET | Secreto usado para autenticar la creación de sesiones. |
| URL del backend | Endpoint de la API de sesiones (referido abajo como https://{HPP_API}). |
| URL del frontend | Origen de la página alojada que corre dentro del iframe (referido abajo como https://{HPP_HOST}). |
El
OAUTH_CLIENT_SECRETnunca debe aparecer en el frontend. Toda la creación de sesiones ocurre en su servidor.
Paso 1 — Crear una sesión de pago (en su backend)
Antes de mostrar el iframe, su servidor crea una sesión. Esta llamada está protegida por OAuth 2.0 Client Credentials (HTTP Basic Auth).
Endpoint: POST /api/sessions/create
Autenticación: encabezado Authorization: Basic base64(clientId:clientSecret)
Parámetros del cuerpo de la solicitud
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
amount | Number | Sí | Monto de la transacción (p. ej. 50.00). Use 0 para card_validation. |
currency | String | Sí | Código de moneda (actualmente solo USD). |
transactionType | String | Sí | payment, card_validation o account_validation. |
parentOrigin | String | Sí | Origen HTTPS de la página que aloja el iframe (p. ej. https://your-site.com). |
capture | Boolean | No | true captura de inmediato; false solo autoriza (predeterminado). |
tokenType | String | No | one_time (predeterminado) o recurring. |
customCss | String | No | URL de un archivo CSS alojado para personalizar la apariencia. |
billingPreference | String | No | Visibilidad de los campos de facturación: editable (predeterminado), read_only o hidden. |
billingDetails | Object | No | Precarga los datos de facturación (nombre, correo, dirección, etc.). |
threeDSData | Object | No | Configuración de 3D Secure: { "enable": true, "successUrl": "...", "failUrl": "..." }. |
metadata | Object | No | Datos de seguimiento de formato libre (p. ej. orderId, customerId, uiOrder). |
Ejemplo (Node.js)
const clientId = process.env.OAUTH_CLIENT_ID;
const clientSecret = process.env.OAUTH_CLIENT_SECRET;
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
const response = await fetch('https://{HPP_API}/api/sessions/create', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 50.00,
currency: 'USD',
transactionType: 'payment',
parentOrigin: 'https://your-site.com',
billingPreference: 'editable',
threeDSData: { enable: true },
metadata: { orderId: 'ORD-789' }
})
});
const session = await response.json();
// Devuelva SOLO el sessionToken a su frontend.
Respuesta
{
"sessionToken": "eyJ...",
"sessionId": "sess_uuid",
"expiresAt": "2026-06-16T12:15:00Z",
"tenant": {
"name": "Your Company",
"logoUrl": "https://...",
"supportEmail": "support@...",
"primaryColor": "#3b82f6",
"paymentMethods": ["card", "ach"]
}
}
El
sessionTokenexpira en 15 minutos por defecto. Cree la sesión solo cuando el cliente esté listo para pagar.
Paso 2 — Cargar el SDK en su frontend
Incluya el script del SDK en la página donde se mostrará el checkout y añada un contenedor (un <div>) donde se montará el iframe.
<!-- Contenedor donde se insertará el iframe -->
<div id="checkout-container"></div>
<!-- SDK del checkout -->
<script src="https://{HPP_HOST}/iframe.min.js"></script>
Paso 3 — Inicializar y montar el iframe
Use el sessionToken obtenido en el Paso 1 para inicializar el SDK y montar el iframe en el contenedor.
<script>
InyoCheckout.init({
sessionToken: 'SESSION_TOKEN_FROM_BACKEND',
// Se invoca cuando el pago es aprobado/autorizado
onSuccess: (data) => {
console.log('Payment approved!', data.transaction);
// data.transaction = { status, paymentId, cardToken, billingInfo }
// IMPORTANTE: confirme en su backend antes de completar el pedido (Paso 5).
},
// Se invoca cuando el pago es rechazado u ocurre un error
onError: (error) => {
console.error('Payment failed:', error);
}
});
InyoCheckout.mount('#checkout-container');
</script>
Opciones aceptadas por init
| Opción | Descripción |
|---|---|
sessionToken | Requerido. Token devuelto en el Paso 1. |
onSuccess(data) | Callback de éxito. Recibe { transaction }. |
onError(error) | Callback de error/rechazo. |
storeLaterUse | true para mostrar la opción de "guardar tarjeta para uso futuro". |
threeDSData | Configuración de 3D Secure (refleja lo enviado en la sesión). |
El
sessionTokenno va en la URL del iframe — el SDK lo envía internamente víapostMessage(INIT_SESSION) después de que el iframe carga. El iframe también se carga en modo sandbox por seguridad.
Paso 4 — Recibir el resultado del pago
Puede manejar el resultado de dos formas (use una o ambas).
Opción A — Callbacks de JavaScript
El SDK dispara onSuccess u onError automáticamente. El objeto data.transaction contiene:
{
status: 'APPROVED' | 'AUTHORIZED' | 'DECLINED' | 'CHALLENGE' | 'PENDING',
paymentId: 'pay_12345',
cardToken: { token: '...', schemeId: 'VISA', lastFourDigits: '4242' },
billingInfo: { /* dirección de facturación completada */ }
}
Ejemplo:
onSuccess: (data) => {
const { status, paymentId } = data.transaction;
if (status === 'APPROVED' || status === 'AUTHORIZED') {
window.location.href = `/confirmation?pid=${paymentId}`;
}
}
Opción B — Redirección (del lado del servidor)
Si proporcionó successUrl / failUrl al crear la sesión (dentro de threeDSData o en la configuración de la sesión), el iframe redirige la página completa al final, agregando los parámetros:
https://your-site.com/success?sessionId=sess_123&paymentId=pay_456
Estados posibles
| Estado | Significado |
|---|---|
AUTHORIZED | Autorizado (aún no capturado). |
APPROVED / CAPTURED | Pago completado. |
DECLINED | Tarjeta rechazada. |
CHALLENGE | Requiere verificación 3D Secure (manejada automáticamente por el iframe). |
PENDING | Pago asíncrono (p. ej. ACH) a la espera de confirmación. |
Paso 5 — Confirmar la transacción en su backend (requerido)
Nunca complete el pedido basándose únicamente en el callback del frontend. Siempre confirme el estado desde su servidor.
Opción 1 — Consultar el estado de la sesión
GET /api/sessions/:sessionId Encabezado: x-session-token: <sessionToken>
const res = await fetch(`https://{HPP_API}/api/sessions/${sessionId}`, {
headers: { 'x-session-token': sessionToken }
});
const session = await res.json();
if (session.status === 'completed') {
// Complete el pedido con seguridad.
}
Opción 2 — Verificar contra el gateway por paymentId
POST /api/verify-transaction Encabezado: x-session-token: <sessionToken> Cuerpo: { "paymentId": "pay_123" }
Personalización visual
La apariencia del checkout es totalmente personalizable:
- CSS personalizado: envíe un
customCss(URL de una hoja de estilos alojada) al crear la sesión para sobrescribir los estilos predeterminados. - Color de marca: definido en el registro del tenant (
primaryColor), aplicado a botones y elementos destacados. - Campos de facturación: controle la visibilidad con
billingPreference(editable,read_only,hidden) y precargue conbillingDetails. - Orden de secciones: controle el orden de las secciones de facturación y pago mediante
metadata.uiOrder(p. ej.["billing", "payment"]).
Comportamiento automático del iframe
- Redimensionamiento: el iframe ajusta su propia altura conforme el contenido cambia (vía el mensaje
RESIZE_IFRAME). No establezca una altura fija. - 3D Secure: cuando se requiere, el iframe maneja la redirección al banco y la verificación ACS automáticamente, validando el resultado en el backend antes de disparar
onSuccess/onError. Vea Manejo de 3D Secure para el comportamiento subyacente del gateway.
Protocolo postMessage (referencia)
El SDK y el iframe se comunican mediante window.postMessage. Normalmente usted no los maneja directamente — el SDK los traduce a los callbacks de init — pero se documentan aquí para depuración.
| Dirección | type del mensaje | Payload |
|---|---|---|
| Padre → iframe | INIT_SESSION | { sessionToken } |
| iframe → Padre | RESIZE_IFRAME | { height } |
| iframe → Padre | PAYMENT_SUCCESS | { transaction } → dispara onSuccess |
| iframe → Padre | PAYMENT_ERROR | { error } → dispara onError |
Lista de verificación de integración
- [ ] Credenciales OAuth (
clientId/clientSecret) guardadas solo en el backend. - [ ] Sesión creada vía
POST /api/sessions/createen el servidor. - [ ]
parentOriginconfigurado correctamente (HTTPS en producción). - [ ] SDK (
iframe.min.js) cargado e iframe montado con elsessionToken. - [ ]
onSuccess/onError(o redirecciones) manejados en el frontend. - [ ] Transacción confirmada en el backend antes de completar el pedido.
Ejemplo completo (condensado)
Backend (crea la sesión):
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
const r = await fetch('https://{HPP_API}/api/sessions/create', {
method: 'POST',
headers: { 'Authorization': `Basic ${credentials}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 29.99,
currency: 'USD',
transactionType: 'payment',
parentOrigin: 'https://your-site.com',
metadata: { orderId: 'ORD-123' }
})
});
const { sessionToken } = await r.json();
// envíe el sessionToken al frontend
Frontend (monta el iframe):
<div id="checkout"></div>
<script src="https://{HPP_HOST}/iframe.min.js"></script>
<script>
InyoCheckout.init({
sessionToken: sessionTokenFromBackend,
onSuccess: async (data) => {
await fetch('/api/confirm-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ paymentId: data.transaction.paymentId })
});
},
onError: (err) => alert('Payment not completed.')
});
InyoCheckout.mount('#checkout');
</script>
