Saltar al contenido principal

Modos de Integración

A continuación veremos cómo implementar los distintos tipos de flujo previamente explicados en la sección Tipos de Flujo.

Cada ejemplo es funcional y listo para usar. Solo necesitás reemplazar la obtención del sessionToken con tu endpoint de backend.

Fundamentos

Todos estos ejemplos usan los conceptos explicados en Fundamentos de Integración. Si no los leíste, te recomendamos hacerlo primero.

API Key solo en el backend

En todos los flujos, el sessionToken se obtiene desde tu backend, que es el único que conoce tu API Key. El frontend nunca debe exponer la API Key directamente.


URLs de los ambientes

Ambienteiframe (integradores)API (sesiones)
PREPRODhttps://iframe-preprod.lakautac.com.arhttps://web-preprod.lakautac.com.ar
PRODhttps://iframe.lakautac.com.ar/embed/https://www.lakautac.com.ar

Obtener Session Token (común a todos los flujos)

Antes de inicializar el iframe, tu frontend debe solicitar un token de sesión a tu backend:

// Tu frontend pide el token a TU backend
async function obtenerSessionToken() {
const response = await fetch('/api/firma/session', { method: 'POST' });
const data = await response.json();
return data.sessionToken;
}

Tu backend internamente llama a la API de Lakaut con tu API Key:

// Tu BACKEND (ejemplo en Node.js)
// PREPROD: https://web-preprod.lakautac.com.ar
// PROD: https://www.lakautac.com.ar
const LAKAUT_WEB_URL = process.env.LAKAUT_WEB_URL;

app.post('/api/firma/session', async (req, res) => {
const response = await fetch(
`${LAKAUT_WEB_URL}/api/integration/session/new?id=TU_INTEGRATOR_ID`,
{
method: 'POST',
headers: { 'X-Api-Key': process.env.LAKAUT_API_KEY }
}
);
const data = await response.json();
res.json({ sessionToken: data.tokenSession });
});

Flujo 1: Modal con Carga Manual

HTML del iframe

<div id="modal-overlay" class="modal-overlay">
<div class="modal-content">
<button class="modal-close" onclick="cerrarModalFirma()"></button>
<iframe
id="lakaut-firma"
src=""
style="width: 100%; height: 500px; border: none;"
allow="clipboard-read; clipboard-write; camera *; microphone"
></iframe>
</div>
</div>

JavaScript

// PREPROD: https://iframe-preprod.lakautac.com.ar
// PROD: https://iframe.lakautac.com.ar/embed/
const IFRAME_ORIGIN = 'https://iframe-preprod.lakautac.com.ar';

const iframe = document.getElementById('lakaut-firma');
let iframeInicializado = false;
let sessionToken = null;

async function abrirModalFirma() {
// 1. Obtener session token desde tu backend
sessionToken = await obtenerSessionToken();

// 2. Cargar el iframe con el token
iframe.src = `${IFRAME_ORIGIN}/embed/?sessionToken=${sessionToken}`;
document.getElementById('modal-overlay').classList.add('active');
}

function cerrarModalFirma() {
document.getElementById('modal-overlay').classList.remove('active');
}

// Escuchar eventos
window.addEventListener('message', (event) => {
if (event.origin !== IFRAME_ORIGIN) return;

const { type, payload } = event.data;

switch (type) {
case 'lakaut.ready':
// Inicializar solo la primera vez
if (!iframeInicializado) {
iframe.contentWindow.postMessage({
type: 'lakaut.init',
payload: {
nonce: crypto.randomUUID(),
idemKey: crypto.randomUUID(),
sessionToken: sessionToken,
userData: {
dni: '12345678',
cuil: '20-12345678-9',
email: 'usuario@tuempresa.com',
gender: 'M',
phone: '1122334455'
}
}
}, IFRAME_ORIGIN);
iframeInicializado = true;
}
break;

case 'lakaut.handshake.ack':
console.log('Conexión establecida');
break;

case 'lakaut.signature.completed':
console.log('Documento firmado:', payload.signedDocId);
cerrarModalFirma();
// Procesar documento firmado
guardarDocumentoFirmado(payload);
break;

case 'lakaut.error':
console.error('Error:', payload);
break;
}
});

Flujo 2: Modal con Carga Automática

HTML del iframe

<div id="modal-overlay" class="modal-overlay">
<div class="modal-content">
<button class="modal-close" onclick="cerrarModalFirma()"></button>
<div id="loading">Cargando documento...</div>
<iframe
id="lakaut-firma"
src=""
style="width: 100%; height: 500px; border: none; display: none;"
allow="clipboard-read; clipboard-write; camera *; microphone"
></iframe>
</div>
</div>

JavaScript

const IFRAME_ORIGIN = 'https://iframe-preprod.lakautac.com.ar';
const iframe = document.getElementById('lakaut-firma');
let contratoActual = null;
let sessionToken = null;

async function firmarContrato(contratoId) {
document.getElementById('modal-overlay').classList.add('active');

// 1. Obtener session token y PDF en paralelo
const [token, pdfBase64] = await Promise.all([
obtenerSessionToken(),
obtenerContratoPDF(contratoId)
]);

sessionToken = token;
contratoActual = { id: contratoId, base64: pdfBase64 };

// 2. Cargar iframe con el token
iframe.src = `${IFRAME_ORIGIN}/embed/?sessionToken=${sessionToken}`;
}

// Escuchar eventos
window.addEventListener('message', (event) => {
if (event.origin !== IFRAME_ORIGIN) return;

const { type, payload } = event.data;

switch (type) {
case 'lakaut.ready':
iframe.contentWindow.postMessage({
type: 'lakaut.init',
payload: {
nonce: crypto.randomUUID(),
idemKey: crypto.randomUUID(),
sessionToken: sessionToken,
userData: {
dni: '12345678',
cuil: '20-12345678-9',
email: 'usuario@tuempresa.com',
gender: 'M',
phone: '1122334455'
}
}
}, IFRAME_ORIGIN);
break;

case 'lakaut.handshake.ack':
console.log('Conexión establecida');

// Cargar el documento automáticamente
if (contratoActual?.base64) {
iframe.contentWindow.postMessage({
type: 'lakaut.load.file',
payload: {
fileName: `Contrato-${contratoActual.id}.pdf`,
mime: 'application/pdf',
base64: contratoActual.base64
}
}, IFRAME_ORIGIN);

document.getElementById('loading').style.display = 'none';
iframe.style.display = 'block';
}
break;

case 'lakaut.signature.completed':
console.log('Documento firmado:', payload.signedDocId);
cerrarModalFirma();
guardarDocumentoFirmado(payload);
break;

case 'lakaut.error':
console.error('Error:', payload);
break;
}
});

// Obtener PDF del backend
async function obtenerContratoPDF(contratoId) {
const response = await fetch(`/api/contratos/${contratoId}/pdf`);
const blob = await response.blob();

return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.readAsDataURL(blob);
});
}

Flujo 3: Vista Embebida con Carga Manual

HTML

<div class="header">
<h1>Mis Documentos</h1>
<p>Seleccioná el documento que necesitás firmar</p>
</div>

<div class="firma-section">
<div id="loading">Inicializando firma...</div>
<iframe
id="lakaut-firma"
src=""
style="width: 100%; height: calc(100vh - 200px); border: 1px solid #ddd; border-radius: 8px; display: none;"
allow="clipboard-read; clipboard-write; camera *; microphone"
></iframe>
</div>

JavaScript

const IFRAME_ORIGIN = 'https://iframe-preprod.lakautac.com.ar';
const iframe = document.getElementById('lakaut-firma');
let sessionToken = null;

// Inicializar al cargar la página
window.addEventListener('load', async () => {
sessionToken = await obtenerSessionToken();
iframe.src = `${IFRAME_ORIGIN}/embed/?sessionToken=${sessionToken}`;
});

// Escuchar eventos
window.addEventListener('message', (event) => {
if (event.origin !== IFRAME_ORIGIN) return;

const { type, payload } = event.data;

switch (type) {
case 'lakaut.ready':
iframe.contentWindow.postMessage({
type: 'lakaut.init',
payload: {
nonce: crypto.randomUUID(),
idemKey: crypto.randomUUID(),
sessionToken: sessionToken,
userData: {
dni: '12345678',
cuil: '20-12345678-9',
email: 'usuario@tuempresa.com',
gender: 'M',
phone: '1122334455'
}
}
}, IFRAME_ORIGIN);

document.getElementById('loading').style.display = 'none';
iframe.style.display = 'block';
break;

case 'lakaut.handshake.ack':
console.log('Conexión establecida');
break;

case 'lakaut.signature.completed':
console.log('Documento firmado:', payload.signedDocId);
mostrarNotificacion('¡Documento firmado exitosamente!');
guardarDocumentoFirmado(payload);
break;

case 'lakaut.error':
console.error('Error:', payload);
mostrarNotificacion('Error: ' + payload.message, 'error');
break;
}
});

function guardarDocumentoFirmado(payload) {
fetch('/api/documentos/firmados', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
signedDocId: payload.signedDocId,
sha256: payload.document.sha256,
size: payload.document.size,
fechaFirma: new Date().toISOString()
})
});
}

Flujo 4: Vista Embebida con Carga Automática

HTML

<div class="header">
<h1>Firmar Contrato</h1>
</div>

<div id="info-contrato" class="info-contrato">
<!-- Se llena dinámicamente -->
</div>

<div class="container">
<div id="loading">Preparando documento para firma...</div>
<iframe
id="lakaut-firma"
src=""
style="width: 100%; height: calc(100vh - 300px); border: 1px solid #ddd; border-radius: 8px; display: none;"
allow="clipboard-read; clipboard-write; camera *; microphone"
></iframe>
</div>

JavaScript

const IFRAME_ORIGIN = 'https://iframe-preprod.lakautac.com.ar';
const iframe = document.getElementById('lakaut-firma');
let contratoData = null;
let sessionToken = null;

// Obtener ID del contrato de la URL
const urlParams = new URLSearchParams(window.location.search);
const contratoId = urlParams.get('id') || 'CONTRATO-001';

// Cargar datos del contrato al iniciar
window.addEventListener('load', async () => {
try {
// Obtener session token, información del contrato y PDF en paralelo
const [token, contrato, pdfBase64] = await Promise.all([
obtenerSessionToken(),
fetch(`/api/contratos/${contratoId}`).then(r => r.json()),
obtenerContratoPDF(contratoId)
]);

sessionToken = token;

// Mostrar información
document.getElementById('info-contrato').innerHTML = `
<h2>${contrato.titulo}</h2>
<p><strong>Número:</strong> ${contrato.numero}</p>
`;

contratoData = {
id: contratoId,
base64: pdfBase64,
nombre: contrato.titulo
};

// Cargar iframe con el token
iframe.src = `${IFRAME_ORIGIN}/embed/?sessionToken=${sessionToken}`;

} catch (error) {
console.error('Error cargando contrato:', error);
document.getElementById('loading').innerHTML =
'<p style="color: red;">Error cargando el contrato.</p>';
}
});

// Escuchar eventos
window.addEventListener('message', (event) => {
if (event.origin !== IFRAME_ORIGIN) return;

const { type, payload } = event.data;

switch (type) {
case 'lakaut.ready':
iframe.contentWindow.postMessage({
type: 'lakaut.init',
payload: {
nonce: crypto.randomUUID(),
idemKey: crypto.randomUUID(),
sessionToken: sessionToken,
userData: {
dni: '12345678',
cuil: '20-12345678-9',
email: 'usuario@tuempresa.com',
gender: 'M',
phone: '1122334455'
}
}
}, IFRAME_ORIGIN);
break;

case 'lakaut.handshake.ack':
console.log('Conexión establecida');

// Cargar el documento automáticamente
if (contratoData?.base64) {
iframe.contentWindow.postMessage({
type: 'lakaut.load.file',
payload: {
fileName: `${contratoData.nombre}.pdf`,
mime: 'application/pdf',
base64: contratoData.base64
}
}, IFRAME_ORIGIN);

document.getElementById('loading').style.display = 'none';
iframe.style.display = 'block';
}
break;

case 'lakaut.signature.completed':
console.log('Documento firmado:', payload.signedDocId);
guardarDocumentoFirmado(payload);
window.location.href = `/contratos/firmado?id=${contratoData.id}`;
break;

case 'lakaut.error':
console.error('Error:', payload);
break;
}
});

async function obtenerContratoPDF(contratoId) {
const response = await fetch(`/api/contratos/${contratoId}/pdf`);
const blob = await response.blob();

return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.readAsDataURL(blob);
});
}

function guardarDocumentoFirmado(payload) {
fetch('/api/contratos/firmados', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contratoId: contratoData.id,
signedDocId: payload.signedDocId,
sha256: payload.document.sha256,
size: payload.document.size,
fechaFirma: new Date().toISOString()
})
});
}

Comparativa de Flujos

FlujoVisualizaciónCargaIdeal para
1ModalManualFirma rápida ad-hoc
2ModalAutomáticaFirma de contrato específico sin salir del contexto
3EmbebidaManualSección dedicada de documentos
4EmbebidaAutomáticaPágina de revisión y firma de documento específico

Convertir PDF a Base64

Si necesitás cargar documentos automáticamente, podés utilizar estas funciones auxiliares:

// Desde un archivo File (input type="file")
async function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
// Remover el prefijo "data:application/pdf;base64,"
const base64 = reader.result.split(',')[1];
resolve(base64);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}

// Desde una URL (tu backend)
async function fetchPdfAsBase64(url) {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}

Próximos pasos