AAPD Widget
Embebe el widget de pago para órdenes AAPD que ve el paciente — integración completa.
El widget AAPD reutiliza la misma infraestructura del widget Spot — cuando minteas un widget token con un order_token, el widget lo detecta y cambia al flujo AAPD.
Qué ve el paciente
pre_start → skip_user / start → select_isapre → select_insurance
→ confirmation → payment_start → payment_capture → successNo controlas la secuencia de pantallas. El widget corre end-to-end y emite un WIDGET_PAYMENT_SUCCESS cuando termina.
Qué construyes
| Paso | Qué |
|---|---|
| 1. Crear orden | POST /orders server-side — ver Crear una orden |
| 2. Mintear widget token | POST /api/spot/widget con order_token (siguiente sección) |
| 3. Renderizar iframe | <iframe> desde el lado paciente (sección "Dimensiones del embed") |
| 4. Escuchar la completitud | window.addEventListener("message", …) (sección "Eventos postMessage") |
Después de que el widget emita éxito, el resto es vía webhooks (order.changed con status = paid, seguimiento ISAPRE, eventual cobro anticipado o liquidación final). El contrato del widget (query params y eventos) está consolidado en Referencia → Parámetros del widget.
Construir la URL del widget
Después de que tu backend cree la orden y mintee el widget token, construye la URL que ve el paciente agregando el order token.
Lo que tienes
Después de las dos llamadas backend:
1. POST /orders → { hash: "2f88b330-f3ed-5521-aa1f-9d15af1fce8d" }
2. POST /api/spot/widget → { widget_token, url: "https://spot.getskip.ai?widget_token=..." }Lo que entregas al paciente
Agrega &order_token={order_hash} a la URL del widget:
https://spot.getskip.ai?widget_token=550e8400-...&public_key=pk_xxx&order_token=2f88b330-f3ed-5521-aa1f-9d15af1fce8dLa presencia de order_token es lo que activa el flujo AAPD dentro del widget. Sin él, el widget trata la sesión como un registro estándar de Spot.
Bootstrap del backend
async function startCnplSession(patient, totalAmountCLP) {
// 1. Crear la orden SkipPay (server-side, credencial secreta)
const orderRes = await fetch("https://pay.getskip.ai/orders", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SKIPPAY_CLIENT_SECRET}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
reference: `MY-ORDER-${Date.now()}`,
total_amount: String(totalAmountCLP),
customer: {
rut: patient.rut,
first_name: patient.firstName,
last_name: patient.lastName,
email: patient.email,
phone_number: patient.phoneNumber,
},
}),
});
const { hash: orderToken } = await orderRes.json();
// 2. Mintear el widget token de Spot (server-side, public_key)
const widgetRes = await fetch(
`https://backend.getskip.ai/api/spot/widget?public_key=${process.env.SKIP_PUBLIC_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
rut: patient.rut,
user_data: {
name: patient.firstName,
surname: patient.lastName,
email: patient.email,
phone_number: patient.phoneNumber,
},
order_token: orderToken,
}),
},
);
const { url: widgetUrl } = await widgetRes.json();
// 3. Agregar order_token para la URL que ve el paciente
const iframeUrl = `${widgetUrl}&order_token=${orderToken}`;
return { iframeUrl, orderToken };
}Devuelve iframeUrl a tu frontend — eso es lo que consume el <iframe src="...">.
Dimensiones del embed
El widget AAPD es una SPA en React renderizada como iframe. Necesita suficiente espacio vertical para formularios, pantallas de pago y vistas de confirmación.
| Pantalla | Ancho mínimo | Alto recomendado |
|---|---|---|
| Móvil | 320 px | 820 px |
| Desktop | 480 px | 820 px |
Embed mínimo
<iframe
src="{iframeUrl}"
width="480"
height="820"
style="border: 0; max-width: 100%;"
allow="clipboard-read; clipboard-write"
title="Widget AAPD de Skip"
></iframe>Patrón modal
La mayoría de partners renderiza el widget dentro de un modal que toma toda la pantalla en móvil:
.skip-modal {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 50;
}
.skip-modal iframe {
width: min(480px, 100vw);
height: min(820px, 100vh);
}CSP
El iframe carga desde https://spot.getskip.ai. Si tu sitio usa Content-Security-Policy, permite frame-src https://spot.getskip.ai;.
Eventos postMessage
El widget AAPD se comunica con la página padre vía postMessage estándar. Suscríbete una vez y despacha por tipo de evento. El vocabulario completo está en Referencia → Parámetros y eventos del widget.
window.addEventListener("message", (event) => {
if (event.origin !== "https://spot.getskip.ai") return;
switch (event.data) {
case "WIDGET_PAYMENT_SUCCESS":
closeIframeModal();
showCnplConfirmation();
break;
case "WIDGET_FORM_CLOSE":
closeIframeModal();
break;
}
});Verifica siempre event.origin — esto es higiene estándar de postMessage. Sin ella, cualquier página embebida puede falsificar estos eventos.
WIDGET_PAYMENT_SUCCESS es la señal frontend de que el paciente terminó. La confirmación autoritativa es tu webhook server-side (order.changed con status = paid). Si tu lógica de negocio requiere "la orden está pagada con seguridad", espera el webhook antes de cumplir. Para UX (cerrar el modal, redirigir, mostrar "¡listo!"), el postMessage está perfecto.