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
}
CampoTipoDescripción
signatureIdstringUUID de la firma creada
documentIdstringUUID del documento
signerEmailstringEmail del firmante
signedAtstringTimestamp 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.
  });
}
CampoTipoDescripción
reason'completed' | 'cancelled' | 'expired' | 'error'Razón de fin de sesión
lastStepstring | nullÚltimo paso completado antes de salir
sessionIdstringID de la Signing Session
documentIdstringUUID del documento
error{ code: string, message: string } | undefinedPresente 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):

EventoCuándo se disparaMetadata
SESSION_STARTEDWidget montado y cargado{}
OTP_SENTCódigo OTP enviado{ channel: 'email' | 'whatsapp' }
OTP_VERIFIEDCódigo OTP verificado{}
ID_SCAN_STARTEDInició escaneo de INE{}
ID_SCAN_COMPLETEDEscaneo terminado{ documentType: 'ine' | 'passport' }
SELFIE_CAPTUREDSelfie capturada{}
BIOMETRIC_VERIFIEDFace match exitoso{ confidence: number }
VARIABLES_FILLEDVariables del formulario completadas{ fieldCount: number }
DOCUMENT_VIEWEDFirmante vio el documento{ pageCount: number }
SIGNATURE_DRAWNFirmante dibujó su firma en el canvas{}
SIGNATURE_SUBMITTEDFirma enviada al servidor{}
SESSION_COMPLETEDFlujo completo terminado{ signatureId: string }

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

EventoCuándo se dispara
signer.signedUn firmante completó su firma
document.completedTodos los firmantes firmaron — PDF final disponible
document.expiredEl documento expiró sin completarse

Ejemplo

POST
/tu-servidor/webhooks
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 });
});

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');
  }
});

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

Was this page helpful?