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
}
CampoTipoDescripción
signatureIdstringUUID de la firma creada
documentIdstringUUID del documento
signerEmailstringEmail del firmante
signedAtstringTimestamp ISO-8601
success_urlstring | nullURL 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.
  });
}
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'
success_urlstring | nullURL de redirección post-firma (si se configuró)
cancel_urlstring | nullURL 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?


onEvidence(evidence)

Se dispara una vez cuando el PDF de evidencia está disponible — es decir, cuando todos los firmantes ya firmaron y la evidencia terminó de generarse. Útil para que muestres o descargues el documento final desde tu propia UI.

onEvidence: (evidence) => {
  // URL presignada de descarga (corta vida). null si no se pudo generar.
  if (evidence.downloadUrl) {
    window.open(evidence.downloadUrl, '_blank');
  }
}
CampoTipoDescripción
signatureIdstringUUID de la firma del firmante actual
documentIdstringUUID del documento completado
downloadUrlstring | nullURL presignada (corta vida) para descargar el PDF de evidencia. null si no se pudo generar (reintenta o usa webhooks)

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):

Esta lista es el conjunto completo de event.name tipados por el SDK (SigningEventName en @allsign/embedded). Es la superficie de contrato: escribe tu onEvent para tolerar cualquiera de estos nombres.

EventoCuándo se disparaMetadata (best-effort)
SESSION_STARTEDWidget montado y cargado{}
OTP_SENTCódigo OTP enviadop.ej. { channel: 'email' | 'whatsapp' }
OTP_VERIFIEDCódigo OTP verificado{}
ID_SCAN_STARTEDInició escaneo de INE/identificación{}
ID_SCAN_COMPLETEDEscaneo terminadop.ej. { documentType: 'ine' | 'passport' }
IDV_STARTEDInició la verificación de identidad (IDV){}
IDV_FAILEDLa verificación de identidad fallóp.ej. { reason: string }
SELFIE_CAPTUREDSelfie capturada{}
BIOMETRIC_VERIFIEDFace match exitosop.ej. { confidence: number }
VIDEO_FIRMA_STARTEDInició la grabación de VideoFirma{}
VIDEO_FIRMA_COMPLETEDVideoFirma grabada{}
NAME_CONFIRMEDFirmante confirmó su nombre{}
VARIABLES_FILLEDVariables del formulario completadasp.ej. { fieldCount: number }
DOCUMENT_VIEWEDFirmante vio el documentop.ej. { pageCount: number }
PIPELINE_STEP_STARTEDInició un paso del pipeline de verificaciónp.ej. { step: string }
PIPELINE_STEP_COMPLETEDSe completó un paso del pipelinep.ej. { step: string, phase: string }
SIGNATURE_DRAWNFirmante dibujó su firma en el canvas{}
FEA_SIGNEDFirma con e.firma SAT (FEA) completada{}
SIGNATURE_SUBMITTEDFirma enviada al servidor{}
SESSION_COMPLETEDFlujo completo terminadop.ej. { 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 },
};

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

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

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
//
// Ojo: los dos eventos usan envelopes distintos.
//   document.completed → { event, document:{...}, pdf:{...} }     (sin clave `data`)
//   signer.signed      → { event, data:{ document, signer, progress } }
app.post('/webhooks/allsign', (req, res) => {
  // El cierre del documento: PDF final + acción de negocio.
  if (req.body.event === 'document.completed') {
    downloadPdf(req.body.pdf.s3_presigned_url);  // PDF final
    activateService(req.body.document.id);         // Acción de negocio
    // ⚠️ document.completed NO trae `data.signer`. Para notificar a un
    // firmante específico usa el evento signer.signed (ver abajo).
  }

  // Notificación por cada firmante: aquí sí existe data.signer.
  if (req.body.event === 'signer.signed') {
    sendConfirmationEmail(req.body.data.signer);   // Notificación
  }

  res.status(200).json({ received: true });
});

Siguiente paso

Was this page helpful?