Eventos y Callbacks
Tres mecanismos complementarios para rastrear la firma: callbacks del SDK para tu UI, webhooks para tu backend, y return URLs para flujos simples.
La regla de oro
Callbacks del SDK son para feedback instantáneo al usuario. Webhooks son la fuente de verdad para tu backend. Return URLs son la alternativa simple cuando no necesitas webhooks.
Nunca tomes acciones críticas (liberar un pago, activar un servicio) basándote solo en callbacks del SDK. Siempre confirma via webhook o return URL.
┌──────────────┐ onSuccess() ┌──────────────┐
│ JS SDK │ ──────────────────────→ │ Tu frontend │ → Actualiza UI
│ (iFrame) │ onEvent() │ │ → Analytics
└──────────────┘ └──────────────┘
│
│ (AllSign server-side)
▼
┌──────────────┐ webhook POST ┌──────────────┐
│ AllSign API │ ──────────────────────→ │ Tu backend │ → Acciones críticas
│ │ │ │
└──────────────┘ └──────────────┘
1. Callbacks del SDK (client-side)
Los callbacks se configuran al montar el widget:
const session = AllSign.init({
clientSecret: 'as_sess_xxx_secret_yyy',
onReady: () => { /* widget cargado */ },
onSuccess: (result) => { /* firmado */ },
onExit: (metadata) => { /* sesión terminó */ },
onEvent: (event) => { /* paso a paso */ },
});
session.modal();
onReady
Se dispara cuando el widget terminó de cargar y el firmante puede interactuar.
onReady: () => {
// Oculta tu skeleton/loader
document.getElementById('loader').style.display = 'none';
}
onSuccess(result)
Se dispara cuando el firmante completó su firma exitosamente.
onSuccess: (result) => {
console.log(result.signatureId); // UUID de la firma
console.log(result.documentId); // UUID del documento
console.log(result.signerEmail); // Email del firmante
console.log(result.signedAt); // Timestamp ISO-8601
}
| Campo | Tipo | Descripción |
|---|---|---|
signatureId | string | UUID de la firma creada |
documentId | string | UUID del documento |
signerEmail | string | Email del firmante |
signedAt | string | Timestamp ISO-8601 |
success_url | string | null | URL de redirección configurada al crear la sesión. Tú controlas cuándo y cómo redirigir. |
onExit(metadata)
Se dispara siempre que la sesión termina, sin importar la razón. Es tu "catch-all" para cleanup.
onExit: (metadata) => {
switch (metadata.reason) {
case 'completed':
showSuccessScreen();
break;
case 'cancelled':
showCancelledMessage();
break;
case 'expired':
refreshAndRetry();
break;
case 'error':
console.error(metadata.error?.code, metadata.error?.message);
break;
}
// metadata.lastStep te dice dónde estaba el firmante cuando salió
analytics.track('signing_exit', {
reason: metadata.reason,
lastStep: metadata.lastStep, // 'otp', 'id_scan', 'signature', etc.
});
}
| Campo | Tipo | Descripción |
|---|---|---|
reason | 'completed' | 'cancelled' | 'expired' | 'error' | Razón de fin de sesión |
lastStep | string | null | Último paso completado antes de salir |
sessionId | string | ID de la Signing Session |
documentId | string | UUID del documento |
error | { code: string, message: string } | undefined | Presente si reason === 'error' |
success_url | string | null | URL de redirección post-firma (si se configuró) |
cancel_url | string | null | URL de redirección post-cancelación (si se configuró) |
lastStep es invaluable para entender dónde abandonan los firmantes: ¿se van en el OTP? ¿En el escaneo de INE? ¿En la firma misma?
onEvent(event) — eventos granulares
Se dispara en cada paso del flujo. Ideal para analytics, progress bars y debugging.
onEvent: (event) => {
// Muestra progreso en tu UI
updateProgressBar(event.name);
// Envía a tu analytics
analytics.track(`allsign_${event.name}`, event.metadata);
}
Eventos disponibles (en orden del flujo):
| Evento | Cuándo se dispara | Metadata |
|---|---|---|
SESSION_STARTED | Widget montado y cargado | {} |
OTP_SENT | Código OTP enviado | { channel: 'email' | 'whatsapp' } |
OTP_VERIFIED | Código OTP verificado | {} |
ID_SCAN_STARTED | Inició escaneo de INE | {} |
ID_SCAN_COMPLETED | Escaneo terminado | { documentType: 'ine' | 'passport' } |
SELFIE_CAPTURED | Selfie capturada | {} |
BIOMETRIC_VERIFIED | Face match exitoso | { confidence: number } |
VARIABLES_FILLED | Variables del formulario completadas | { fieldCount: number } |
DOCUMENT_VIEWED | Firmante vio el documento | { pageCount: number } |
SIGNATURE_DRAWN | Firmante dibujó su firma en el canvas | {} |
SIGNATURE_SUBMITTED | Firma enviada al servidor | {} |
SESSION_COMPLETED | Flujo completo terminado | { signatureId: string } |
No todos los eventos se disparan en todas las sesiones. Si no configuraste OTP, no verás OTP_SENT. Si no hay verificación de identidad, no verás ID_SCAN_*. Los eventos reflejan los pasos reales del pipeline configurado.
Ejemplo: Progress bar con onEvent
const steps = {
'SESSION_STARTED': { label: 'Cargando...', progress: 10 },
'OTP_VERIFIED': { label: 'Identidad verificada', progress: 25 },
'ID_SCAN_COMPLETED': { label: 'INE escaneada', progress: 50 },
'BIOMETRIC_VERIFIED': { label: 'Biométricos verificados', progress: 65 },
'DOCUMENT_VIEWED': { label: 'Revisando documento', progress: 80 },
'SIGNATURE_SUBMITTED': { label: 'Firmando...', progress: 95 },
'SESSION_COMPLETED': { label: 'Completado', progress: 100 },
};
const session = AllSign.init({
clientSecret,
onEvent: (event) => {
const step = steps[event.name];
if (step) {
progressBar.style.width = `${step.progress}%`;
statusText.textContent = step.label;
}
},
});
session.inline('#container');
2. Webhooks (server-side)
Los webhooks envían un POST a tu servidor cuando ocurren eventos. Configúralos desde el Dashboard o vía la API de Webhooks.
Eventos relevantes para Embedded Signing
| Evento | Cuándo se dispara |
|---|---|
signer.signed | Un firmante completó su firma |
document.completed | Todos los firmantes firmaron — PDF final disponible |
document.expired | El documento expiró sin completarse |
Ejemplo
app.post('/webhooks/allsign', (req, res) => {
const event = req.body.event;
if (event === 'signer.signed') {
const { signer, progress } = req.body.data;
console.log(`${signer.name} firmó — ${progress.completed}/${progress.total}`);
}
if (event === 'document.completed') {
const pdf = req.body.pdf;
downloadSignedPdf(pdf.s3_presigned_url);
markContractCompleted(req.body.document.id);
}
res.status(200).json({ received: true });
});
Para la referencia completa de webhooks (todos los eventos, payloads, seguridad HMAC), consulta la documentación de Webhooks.
3. Return URLs (metadata para redirección)
Si configuraste success_url o cancel_url al crear la Signing Session, AllSign las incluye como metadata en los callbacks onSuccess y onExit. AllSign no redirige automáticamente — tú controlas el timing y la UX del redirect en tu propio código.
Cómo llegan las URLs
onSuccess: (result) => {
// result.success_url viene si la configuraste en POST /v2/signing-sessions
showThankYouMessage();
if (result.success_url) {
// Tú decides cuándo redirigir
setTimeout(() => {
window.location.href = result.success_url;
}, 2000);
}
}
onExit: (metadata) => {
if (metadata.reason === 'cancelled' && metadata.cancel_url) {
window.location.href = metadata.cancel_url;
}
}
Configurar las URLs
Las URLs se configuran al crear la sesión:
const session = await fetch('https://api.allsign.io/v2/signing-sessions', {
method: 'POST',
headers: { 'Authorization': 'Bearer allsign_live_sk_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
document_id: '550e8400-...',
signer_email: 'juan@empresa.com',
success_url: 'https://tuapp.com/firmado', // opcional
cancel_url: 'https://tuapp.com/cancelado', // opcional
})
});
¿Por qué no redirigimos automáticamente? Porque el iframe no puede navegar al parent (cross-origin security), y forzar un redirect te quita control del UX. Tú puedes mostrar una pantalla de éxito, hacer animaciones, llamar a /verify para obtener la evidencia, y luego redirigir cuando sea el momento correcto.
SSE: Eventos en tiempo real (avanzado)
AllSign también ofrece Server-Sent Events (SSE) para actualizaciones en tiempo real desde tu backend — sin polling y con menos latencia que webhooks.
// 1. Obtén un token SSE desde tu backend
const { token } = await fetch('/api/sse-token', {
method: 'POST',
body: JSON.stringify({ documentId })
}).then(r => r.json());
// 2. Conéctate al stream
const eventSource = new EventSource(
`https://api.allsign.io/v2/sse/stream?token=${token}`
);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('SSE:', data.type);
// 'signer_signed', 'document_completed', 'status_changed'
};
Patrón recomendado: Callbacks + Webhooks
La integración más robusta usa callbacks para la UI y webhooks para el backend:
// Frontend: feedback instantáneo
const session = AllSign.init({
clientSecret,
onSuccess: () => {
showConfirmation(); // Instantáneo — el usuario ve que firmó
},
onEvent: (e) => {
trackAnalytics(e); // Cada paso del flujo
},
});
session.modal();
// Backend: fuente de verdad
app.post('/webhooks/allsign', (req, res) => {
if (req.body.event === 'document.completed') {
downloadPdf(req.body.pdf.s3_presigned_url); // PDF final
activateService(req.body.document.id); // Acción de negocio
sendConfirmationEmail(req.body.data.signer); // Notificación
}
res.status(200).json({ received: true });
});
Siguiente paso
- Seguridad — Signing Sessions, CSP y validación
- JS SDK Reference — API completa del SDK

