Webhooks
Con los webhooks, bb-sign envía un payload JSON firmado a su URL cada vez que cambia el estado de un sobre, y su sistema reacciona al instante sin consultas periódicas.
El esquema de firma se define de forma normativa en la especificación de firma de webhooks; esta página es la guía de integración.
Registrar un webhook
Sección titulada «Registrar un webhook»En Configuración, pestaña Webhooks, seleccione Nuevo webhook.
- URL del endpoint: «Debe ser HTTPS y accesible desde internet. Rechazamos direcciones privadas e internas». La validación se repite en cada entrega.
- Eventos que quieres recibir: seleccione los que necesite entre los seis disponibles:
| Evento | Cuándo |
|---|---|
envelope.sent |
Un sobre se envió a sus firmantes |
envelope.completed |
Todos los firmantes firmaron |
envelope.cancelled |
Un sobre se canceló |
envelope.expired |
Un sobre llegó a su fecha de vencimiento sin completarse |
signer.signed |
Un firmante firmó; otros pueden estar pendientes |
signer.viewed |
Un firmante abrió el documento |
El secreto de firma se muestra una sola vez, al crear el webhook. Guárdelo en su gestor de secretos. Una organización puede tener hasta 20 webhooks.
Contenido de la entrega
Sección titulada «Contenido de la entrega»{ "id": "3f8c...", "type": "envelope.completed", "apiVersion": "2026-08-09", "createdAt": "2026-08-09T14:22:31Z", "data": { "envelope": { "id": "...", "title": "Q3 Agreement", "status": "COMPLETED", "createdAt": "...", "expiresAt": null }, "signer": { "id": "...", "email": "...", "name": "...", "signOrder": 1, "status": "SIGNED", "signedAt": "..." } }}data.signer se incluye solo en los eventos signer.*. Los esquemas completos figuran en la
referencia de la API como WebhookEvent, de modo que un cliente generado los recibe
tipados.
Cada entrega incluye tres encabezados:
| Encabezado | Uso |
|---|---|
X-BBSign-Signature |
La firma que se verifica. t=<unix>,v1=<hex> |
X-BBSign-Event-Id |
Su clave de idempotencia, estable entre reintentos |
X-BBSign-Event-Type |
El nombre del evento, para enrutar antes de interpretar el cuerpo |
Obtener el documento firmado
Sección titulada «Obtener el documento firmado»Al recibir envelope.completed, llame a GET /api/v1/envelopes/{id}/documents para obtener el
archivo. La respuesta incluye signedUrl cuando el sobre está COMPLETED, válido durante
3.600 s. El payload no incluye enlaces de descarga a
propósito: un enlace prefirmado dentro del payload seguiría siendo útil después de la entrega y
podría quedar guardado en registros. El
recorrido completo muestra toda la secuencia.
Verificar la firma sobre el cuerpo original
Sección titulada «Verificar la firma sobre el cuerpo original»La firma cubre los bytes exactos recibidos. La mayoría de los frameworks web interpretan el JSON antes de entregarlo al handler, y volver a serializar ese objeto produce bytes distintos (cambian el orden de las claves y los espacios), por lo que la verificación falla aunque el objeto sea correcto. Capture el cuerpo original antes de cualquier interpretación.
import { verifyWebhookSignature } from '@binarybridges/bb-sign-sdk/webhooks'
app.use(express.json({ verify: (req, _res, buf) => { req.rawBody = buf } }))
app.post('/webhooks/bb-sign', (req, res) => { if (!verifyWebhookSignature(req.get('X-BBSign-Signature'), req.rawBody, SECRET)) { return res.sendStatus(401) } res.sendStatus(200) void handle(JSON.parse(req.rawBody.toString('utf8')))})En Next.js, use await request.text() en lugar de .json(). En Fastify, registre un parser de
content-type con parseAs: 'buffer'. La página del SDK de JavaScript
incluye ambos ejemplos completos.
@PostMapping("/webhooks/bb-sign")public ResponseEntity<Void> receive( @RequestHeader("X-BBSign-Signature") String signature, @RequestBody byte[] rawBody) { // byte[], NOT a DTO
if (!Webhooks.verify(signature, rawBody, System.getenv("BBSIGN_WEBHOOK_SECRET"))) { return ResponseEntity.status(401).build(); } WebhookEvent event = new ObjectMapper().readValue(rawBody, WebhookEvent.class); // ... handle asynchronously return ResponseEntity.ok().build();}La página del SDK de Java explica por qué el parámetro es byte[].
Implementar un verificador propio
Sección titulada «Implementar un verificador propio»La especificación es normativa y breve. Tres requisitos merecen atención especial:
- Comparar en tiempo constante. Un
==sobre el digest revela, byte a byte, qué parte de una firma falsificada es correcta, y eso basta para construir una válida. - Comprobar la marca de tiempo. Sin comprobación de vigencia, una entrega capturada podría reenviarse indefinidamente.
- Aceptar cualquier
v1que coincida. Durante una rotación del secreto, el encabezado lleva dos valores; exigir que coincida el primero anula la ventana de rotación.
Los vectores de prueba incluyen 16 casos, entre ellos los que deben fallar. El servidor y ambos SDKs se prueban contra ese mismo archivo; pruebe también su verificador contra él.
Entrega y reintentos
Sección titulada «Entrega y reintentos»Responda 2xx de inmediato y procese después. Confirme la recepción en cuanto la firma sea válida y procese el evento de forma asíncrona.
Reintentos. Una entrega fallida se reintenta con una secuencia de esperas que abarca
aproximadamente 15 horas, con esperas de
1m, 5m, 30m, 2h, 12h. Cualquier 2xx
cuenta como éxito; cualquier otra respuesta, como fallo.
Desactivación automática. Tras 3 entregas consecutivas que agotan sus reintentos, la suscripción se desactiva y los administradores de la organización reciben un correo. El panel muestra el estado Desactivado automáticamente, con la nota: «Desactivamos este endpoint después de que sus reintentos fallaran repetidamente. Corrígelo y vuelve a activarlo». bb-sign también prueba el endpoint cada 6 horas, y una respuesta exitosa lo reactiva.
Eventos durante la desactivación. Se registran como No enviado y no se acumulan para después, de modo que su sistema no recibe una avalancha de eventos antiguos al reactivarse. El historial muestra exactamente qué eventos no se entregaron.
Entrega al menos una vez. Un mismo evento puede llegar dos veces, por ejemplo tras un corte de
red o un reinicio. X-BBSign-Event-Id es idéntico en ambos casos; úselo para eliminar duplicados.
Cuerpo estable entre reintentos. El cuerpo se genera una sola vez y se reenvía byte por byte,
de modo que un envelope.sent reintentado horas después describe el momento del envío. Solo se
recalcula la firma, porque incluye la hora de entrega.
Consultar el historial de entregas
Sección titulada «Consultar el historial de entregas»En Configuración, pestaña Webhooks, Historial muestra cada evento, cada intento, el código de respuesta y el error. Las entradas se conservan durante 90 días. Es el primer lugar para diagnosticar una entrega:
| Estado | Significado | Acción |
|---|---|---|
| Entregado | El evento llegó y su endpoint respondió 2xx | Ninguna |
| Rechazado / Inaccesible | Su endpoint respondió con error o no respondió; la lista de intentos indica cuál | Revise sus registros para ese intento; el siguiente reintento ya está programado |
| Abandonado | Se agotaron los reintentos | Corrija el endpoint y consulte el estado del sobre con la API; este evento no se reenvía |
| No enviado | El endpoint estaba desactivado en ese momento | Active el endpoint y concilie el periodo con GET /api/v1/envelopes |
| No se pudo construir | Un error del lado de bb-sign | Contacte a soporte |
Rotar el secreto
Sección titulada «Rotar el secreto»En Configuración, pestaña Webhooks, seleccione Rotar secreto. «Se aceptarán tanto el
secreto antiguo como el nuevo durante un periodo de gracia, así que tu receptor seguirá
funcionando hasta que lo despliegues con el nuevo». El periodo de gracia es de
24 horas. Las entregas en esa ventana llevan
dos valores v1; un verificador correcto acepta cualquiera de los dos, como hacen ambos SDKs.
Probar el endpoint
Sección titulada «Probar el endpoint»Enviar prueba entrega un evento sintético a su endpoint y muestra el código de estado de la respuesta. Usa el mismo proceso de firma que las entregas reales, de modo que valida su verificador de extremo a extremo.