Checkout web y app
@finora/checkout es un Web Component sin dependencias (~18 KB min+gz) que dibuja la experiencia de pago de FINORA dentro de tu página: «¿Cómo quieres pagar?», tarjetas grandes por medio, campos guiados, espera al terminal, recibo. Es la misma experiencia de FINORA Caja y de la página alojada pago.finoracore.com, así que tu cliente la reconoce.
Instalación
<script src="https://pago.finoracore.com/sdk/finora-checkout.js"></script>
<!-- registra <finora-checkout> y el global FinoraCheckout -->
npm i @finora/checkout
import { FinoraCheckout } from "@finora/checkout"; // registra <finora-checkout> al importar
Navegadores: Chrome/Edge 90+, Safari 15+, Firefox 90+. El SDK no carga fuentes, scripts ni imágenes externas: habla solo con base-url. Si tu CSP es estricta: connect-src https://pos.finoracore.com.
Tres formas de mostrarlo
A. Redirigir a urlPago
La respuesta de POST /api/v1/checkout/sesiones trae urlPago. Redirige al cliente y listo: al terminar vuelve a tu returnUrl con ?sesion={sesionId}&estado={estado}. La página alojada muestra el nombre de tu comercio en la cabecera.
B. <finora-checkout> en tu página
<finora-checkout sesion="cs_…" token="tok_…" base-url="https://pos.finoracore.com"
tema="claro" idioma="es" teclado="auto" style="height: 40rem"></finora-checkout>
| Atributo | Valores | Por defecto | Qué hace |
|---|---|---|---|
sesion | id de sesión | obligatorio | La sesión que creó tu servidor. |
token | token de cliente | obligatorio | Solo sirve para esa sesión; vence con ella. |
base-url | URL | origen de la página | Raíz del Merchant: https://pos.finoracore.com. |
tema | claro · oscuro · auto | claro | auto sigue prefers-color-scheme. |
idioma | es · en | idioma del navegador | Textos del SDK. Los nombres de los medios vienen del Merchant. |
teclado | auto · siempre · nunca | auto | Teclado numérico en pantalla para cédula, teléfono y clave (auto = solo táctil). |
modo | incrustado · pantalla | incrustado | pantalla lo usa la página alojada. |
El componente llena la altura de su contenedor: dale height. Por debajo de 760 px de ancho el resumen pasa a una barra superior y los medios a una columna.
C. Modal con FinoraCheckout.abrir
const instancia = FinoraCheckout.abrir({
sesionId, token, baseUrl: "https://pos.finoracore.com",
modal: true, // por defecto si no hay `contenedor`
contenedor: "#pago", // elemento o selector; desactiva el modal
tema: "claro", idioma: "es",
onSesion: (sesion) => {}, // monto, comercio, medios: para pintar tu cabecera
onResultado: (r) => {}, // { sesionId, estado, riel, codigo, mensaje, autorizacion, recibo }
onCancelar: () => {},
onError: (e) => console.error(e.codigo, e.mensaje),
});
instancia.cancelar(); // cancela en el servidor
instancia.cerrar(); // desmonta sin cancelar (por ejemplo, tras onResultado)
Como modal: capa sobre la página (role="dialog", aria-modal), foco atrapado, Escape cancela solo mientras no hay dinero en vuelo. Tras onResultado cierra tú con cerrar() cuando hayas mostrado lo que quieras; el cliente ve el recibo hasta entonces.
Eventos
Todos son CustomEvent, burbujean y cruzan el shadow DOM.
| Evento | detail | Cuándo |
|---|---|---|
finora-sesion | SesionDto | Se cargó la sesión: monto, comercio, medios. |
finora-resultado | { sesionId, estado, riel, codigo, mensaje, autorizacion, recibo } | La sesión terminó. estado ∈ APROBADA · RECHAZADA · EN_DUDA · CANCELADA · EXPIRADA; codigo es el DE 39 del banco («00», «51») o el motivo (CANCELADA_POR_CLIENTE). |
finora-cancelar | — | El cliente canceló. |
finora-error | { codigo, mensaje } | Error que impide seguir: TOKEN_INVALIDO, SESION_NO_ENCONTRADA, red al cargar. |
finora-resultado es JavaScript en el navegador del cliente. Entrega el pedido con el webhook firmado o consultando GET /api/v1/checkout/sesiones/{id} con tu clave.
Lo que hace por dentro
GET /api/v1/checkout/sesiones/{id} ← medios, monto, campos requeridos
(cédula si payerIdMode = ANTES_DE_MEDIOS y no vino en `pagador`)
selector de medios · formulario por riel (campos desde `campos[]`)
POST /api/v1/checkout/sesiones/{id}/medio ← { riel, campos, tipoDocumento?, documento? }
GET /api/v1/checkout/sesiones/{id}/estado ← cada 2 s mientras haya un cobro en vuelo
POST /api/v1/checkout/sesiones/{id}/cancelar ← «Cancelar»
Reglas de la experiencia, heredadas de FINORA Caja:
- Los medios no disponibles se ven atenuados con su motivo («Mínimo Bs 500,00», «Sin terminal asignado»), no se esconden.
RECHAZADAes final. Crea otra sesión si el cliente quiere intentar con otro medio.- Lo único que reabre el selector es el terminal que no toma la orden: la sesión vuelve a
CREADAconcodigo = TERMINAL_SIN_RESPUESTA. EN_DUDAno ofrece reintentar: «no vuelvas a pagar». Reintentar un cobro que pudo ocurrir es cobrar dos veces.- Sin campo de tarjeta en ningún sitio. Tarjeta = «paga en el terminal» (
terminalIdde la sesión, por ejemploTERM0042).
Tema
El componente vive en un shadow root: tu CSS no lo toca. Lo único que lo atraviesa son las custom properties --fc-*:
finora-checkout {
--fc-color-primary: #0b6e4f; /* botón principal, borde al pasar */
--fc-color-primary-contrast: #fff;
--fc-color-accent: #ffb703; /* anillo de foco, paso activo del terminal */
--fc-font: "Inter", system-ui, sans-serif;
--fc-radius: 8px;
}
finora-checkout[tema="oscuro"] { --fc-color-bg: #000; }
Tokens disponibles: --fc-color-{primary,primary-contrast,accent,bg,surface,surface-2,text,text-2,text-3,line,line-2,ok,ok-bg,error,error-bg,warn,warn-bg}, --fc-font, --fc-font-mono, --fc-radius, --fc-radius-sm, --fc-shadow, y --fc-tint-{tarjeta,movil,transferencia,efectivo,qr,cripto,otro} para el icono de cada medio. La composición y los textos no se cambian a propósito: el cliente los reconoce de la Caja.
Accesibilidad
role="region" con etiqueta, un h1 por paso, aria-live en la espera, role="alert" en errores, aria-invalid + aria-describedby en campos, foco al primer campo o al primero con error, teclas de 4,25 rem, contraste AA, prefers-reduced-motion respetado. En kiosco o tableta, con puntero táctil aparece el teclado numérico en pantalla.
Kiosco y app nativa
En una WebView (Android, iOS, Electron) funciona igual: la app pide la sesión a tu servidor y monta el componente. Para una caja de escritorio en Windows que no quiera tocar HTML, mira FINORA Pago: la misma sesión, orquestada por una aplicación instalable con API local.