Embed
Crea una sesión server-side y monta el Web Component con aislamiento de origen.
Esta página es la referencia del mecanismo. Si buscas el recorrido completo paso a paso, empieza por el flujo de consentimiento general o el flujo REDEC.
El flujo mantiene separadas las credenciales del integrador y el token temporal del runtime:
Backend integrador → POST /v1/embed/sessions
Frontend → <consensa-consent>
Runtime Consensa → bootstrap, identidad y decisión
Frontend → eventos públicos sanitizadosAntes de crear la sesión: metadata del Flow
GET /v1/embed/flows/{configKey} (scope consent:runtime) devuelve la versión publicada vigente del Flow: consentimientos, política de autenticación congelada, identifiers requeridos y, si el Flow contiene REDEC, las finalidades y objetivos admitidos por el Regulatory Profile. Envía el header Origin de la página host; origin.allowed es informativo y POST /v1/embed/sessions sigue siendo el punto de enforcement. No crea sesión, interacción ni consentimiento.
1. Crear la sesión
Ejecuta esta llamada desde tu backend. origin debe coincidir exactamente con un origen permitido para el tenant.
La operación requiere consent:runtime. El ejemplo afirma que el banco ya autenticó al cliente con authentication.source: "client", por lo que la API key necesita además consent:identity-assert. Con source: "consensa", ese scope adicional no es requisito de creación y el runtime gestiona la verificación.
curl --request POST "$CONSENSA_API_URL/v1/embed/sessions" \
--header "Authorization: Bearer $CONSENSA_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: embed-customer-4821-01" \
--data '{
"configKey": "general-consent",
"userReference": "customer-4821",
"origin": "https://banco.ejemplo.cl",
"authentication": {
"source": "client",
"method": "bank_session",
"authenticatedAt": 1787702400000,
"reference": "session-reference-8f2a"
}
}'La respuesta es un pre-check. Si presentation.required es false, no hace falta una nueva interacción de consentimiento según el estado evaluado en ese instante: continúa el flujo y no montes el componente. En ese caso Consensa no crea sesión ni tokens de interacción.
Este resultado no autoriza la operación. Puede existir una ventana entre el pre-check y el tratamiento: el consentimiento puede revocarse, expirar o cambiar. Para General ejecuta /v1/authorization/check, cuando corresponda, inmediatamente antes de la operación. Para REDEC conserva el gate regulatorio especializado inmediatamente antes del acceso CMF. Una revocación o expiración posterior al pre-check siempre debe respetarse.
Si presentation.required es true, la respuesta incluye sessionId, interactionId, launchTicket, launchExpiresAt y expiresAt. launchTicket no es una credencial de sesión: es un ticket de un solo uso que vence a los 60 segundos. Pídelo justo antes de montar el componente, no lo registres, no lo persistas y nunca lo pongas en un atributo HTML ni en una URL.
Errores propios de esta operación
| Estado | error.message | Qué revisar |
|---|---|---|
400 | idempotency_key_required | Falta el header Idempotency-Key. |
400 | customer_rut_required_for_identity_verification | El perfil publicado incluye cédula y el cliente no tiene identifier {system: cl, type: rut}. |
400 | redec_notification_email_required / _ambiguous | El Flow REDEC delega la notificación en Consensa y falta, o sobra, el identifier de email. |
403 | ORIGIN_NOT_ALLOWED | origin no es un origen permitido y activo del tenant. |
403 | REDEC_NOT_ENABLED | El producto REDEC no está habilitado para tu tenant. |
404 | CONFIG_NOT_FOUND / CONFIG_NOT_PUBLISHED | El configKey no existe o no tiene versión publicada utilizable. |
422 | verified_customer_rut_required_for_redec | Flow REDEC con source: "client": el cliente necesita un RUT verificado, no sólo presente. |
2. Montar el componente
Ejecuta esta sección sólo cuando presentation.required === true.
Carga el bundle host, crea el elemento con la URL de runtime del ambiente y el sessionId (no es secreto), y entrega el ticket con launch(). El componente monta un iframe Consensa cross-origin y le pasa el ticket por postMessage sólo después de que el runtime se anuncia. El runtime lo canjea una única vez, ligado al origen de tu página que certifica el navegador, por la credencial real de la sesión. Esa credencial vive sólo dentro del iframe: ni tu código, ni scripts de terceros ni herramientas de session replay pueden leerla.
<script type="module" src="https://embed.consensa.example/host.js"></script>
<div id="consent-slot"></div>
<script type="module">
const consent = document.createElement('consensa-consent');
consent.setAttribute('title', 'Consentimiento para solicitud de crédito');
consent.setAttribute('src', 'https://embed.consensa.example/runtime.html');
consent.setAttribute('session', sessionId);
document.querySelector('#consent-slot').replaceChildren(consent);
consent.launch(launchTicket);
</script>El elemento observa tres atributos: src (URL del runtime), session (el sessionId) y title (el título accesible del iframe). El ticket se entrega sólo por launch().
El runtime sólo acepta ser enmarcado por el origen exacto con el que creaste la sesión (Content-Security-Policy: frame-ancestors), también cuando tu página está a su vez dentro de otro frame. Si tu página no corre en ese origen, el canje falla con ORIGIN_NOT_ALLOWED y el componente muestra el estado inválido. Si el ticket venció (consensa:expired), crea una nueva sesión desde tu backend. runtime.html es un recurso técnico provisto por Consensa: el runtime siempre llama a la API por su propio origen y no admite otro destino. Los endpoints usados por el iframe son administrados por Consensa y no forman parte de la Integration API.
3. Escuchar el resultado
Todos los eventos llevan detail.interactionReference, una referencia opaca de la interacción.
| Evento | Cuándo se emite | detail adicional |
|---|---|---|
consensa:ready | El runtime cargó y está listo. | — |
consensa:granted | Interacción de un consentimiento, otorgado. | outcome: "granted" |
consensa:denied | Interacción de un consentimiento, denegado. | outcome: "denied" |
consensa:completed | Interacción de dos o más consentimientos. | outcome: "completed", consents[] |
consensa:cancelled | El titular salió sin decidir. | outcome: "cancelled" |
consensa:expired | Venció el ticket o la sesión. | outcome: "expired" |
consensa:error | Error sanitizado. | code |
consensa:resize | El contenido cambió de alto. | width, height |
consent.addEventListener('consensa:granted', ({ detail }) => {
console.log(detail.interactionReference, detail.outcome);
});
consent.addEventListener('consensa:denied', ({ detail }) => {
console.log(detail.interactionReference, detail.outcome);
});Los eventos son notificaciones sanitizadas para la interfaz. Confirma siempre el resultado de negocio desde tu backend mediante la API de Consentimiento.
Seguridad del canal
El host valida el origen exacto del runtime, el source exacto del iframe y la versión del protocolo. Consensa nunca usa postMessage("*") y no expone tokens, identificadores internos ni datos personales en eventos públicos.