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
│ │ ─ o ─ │ │
│ │ redirect a │ │
│ │ success_url?status= │ │
└──────────────┘ └──────────────┘
1. Callbacks del SDK (client-side)
Los callbacks se configuran al montar el widget:
allsign.modal({
clientSecret: 'as_sess_xxx_secret_yyy',
onReady: () => { /* widget cargado */ },
onSuccess: (result) => { /* firmado */ },
onExit: (metadata) => { /* sesión terminó */ },
onEvent: (event) => { /* paso a paso */ },
});
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 |
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' |
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 },
};
allsign.inline('#container', {
clientSecret,
onEvent: (event) => {
const step = steps[event.name];
if (step) {
progressBar.style.width = `${step.progress}%`;
statusText.textContent = step.label;
}
},
});
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 (la alternativa simple)
Si no quieres configurar webhooks, usa las URLs de retorno que configuraste al crear la Signing Session. AllSign redirige al firmante con query params que contienen el resultado:
success_url
https://tuapp.com/firmado?session_id=as_sess_xxx&status=completed&document_id=550e8400&signer_email=juan@empresa.com&signature_id=9a8b7c6d
cancel_url
https://tuapp.com/cancelado?session_id=as_sess_xxx&status=cancelled&document_id=550e8400&last_step=signature
Usar return URLs en tu backend
// Next.js API route o Express handler
app.get('/firmado', (req, res) => {
const { session_id, document_id, signature_id, status } = req.query;
if (status === 'completed') {
markContractSigned(document_id);
res.redirect('/dashboard?signed=true');
}
});
Las return URLs funcionan incluso si el widget se cierra inesperadamente, porque AllSign redirige al firmante al terminar. Para el modo modal/slider, el SDK intercepta la redirección y dispara onSuccess/onExit en su lugar.
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
allsign.modal({
clientSecret,
onSuccess: () => {
showConfirmation(); // Instantáneo — el usuario ve que firmó
},
onEvent: (e) => {
trackAnalytics(e); // Cada paso del flujo
},
});
// 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

