EN VIVO · CON AUDITORÍA · UE
SISTEMA · 99,99% UPTIME
v 1.0 ↗ HECHO EN UE

Webhooks

Los webhooks son la forma en que su backend se entera de cosas que ocurren de forma asíncrona: sesiones que terminan, grabaciones que finalizan el posprocesado, cadenas de auditoría que se anclan en la TSA. Registre una URL, verifique la firma en cada POST y despache según el tipo de evento.

Tipos de evento

EventoCuándo
session.createdNueva sesión mediante la SPA o la API pública
session.completedSesión finalizada (manualmente o mediante la API)
participant.joinedUn usuario de campo (u observador) se unió a una sesión
participant.leftUn participante se desconectó
evidence.addedNueva captura / anotación / pizarra / clip / documento capturado
recording.readyArtefactos de grabación posprocesados disponibles
audit.anchoredCabecera de la cadena anclada en una de las TSA configuradas
signature.completedUn PDF firmado (SES/AES/QES) está listo para descargar
webhook.testDisparado por el botón «Test fire» en el admin de la SPA, con un payload sintético mínimo

Forma del sobre

{
  "id": "evt_01HGB9...",
  "type": "session.completed",
  "created_at": "2026-05-23T11:42:15Z",
  "org_id": 42,
  "data": {
    /* event-specific payload — full resource shape */
  }
}

El id es estable entre reintentos: úselo como su clave de idempotencia en el lado del receptor.

Cabecera de firma

Cada POST lleva una cabecera NB-Signature en un formato al estilo de Stripe:

NB-Signature: t=1716461235,v1=5257a8...3e2c1f

El valor v1 es HMAC-SHA256(secret, "{timestamp}.{body}") en hexadecimal. El valor t es un sello de tiempo Unix en el momento de la firma. Una ventana de tolerancia de 5 minutos rechaza el reenvío de payloads antiguos.

Verificación en código

Node

import { NexBasira, InvalidSignatureError } from "@nexbasira/node";

const nb = new NexBasira({ apiKey: "...", apiSecret: "..." });

// Express handler — important: use express.raw() so the body is the
// untouched bytes the signature was computed over.
app.post("/nb-webhook", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.header("NB-Signature")!;
  const secret = process.env.NB_WEBHOOK_SECRET!;
  let event;
  try {
    event = nb.webhooks.constructEvent(req.body, sig, secret);
  } catch (err) {
    if (err instanceof InvalidSignatureError) {
      return res.status(401).send("bad signature");
    }
    throw err;
  }
  // event is now type-narrowed by event.type
  return handleEvent(event, res);
});

Python

from nexbasira import NexBasira, InvalidSignatureError

nb = NexBasira(api_key="...", api_secret="...")

# Flask handler — get the raw body, not request.get_json()
@app.post("/nb-webhook")
def webhook():
    sig = request.headers["NB-Signature"]
    secret = os.environ["NB_WEBHOOK_SECRET"]
    try:
        event = nb.webhooks.construct_event(request.data, sig, secret)
    except InvalidSignatureError:
        return ("bad signature", 401)
    return handle_event(event)

Comportamiento de reintento

Una entrega se considera correcta cuando su endpoint devuelve un 2xx en menos de 30 s. Cualquier otra cosa desencadena un backoff exponencial:

30s 5m 1h 6h 24h DROPPED

Tras 50 fallos consecutivos en todos los eventos, el endpoint se desactiva automáticamente. El administrador de la organización puede reactivarlo desde el admin de la SPA una vez que el receptor vuelva a estar operativo.

Idempotencia en su lado

Las entregas de webhooks pueden repetirse. Trate event.id como la clave de deduplicación:

-- Postgres example
INSERT INTO webhook_deliveries (event_id, processed_at)
VALUES ($1, NOW())
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id;
-- If RETURNING is empty, this is a duplicate — skip the side-effect.

Secretos de firma

Cada endpoint de webhook registrado tiene su propio secreto de firma whsec_*. El texto plano se muestra exactamente una vez cuando registra el endpoint (o lo rota); a partir de entonces almacenamos una copia cifrada con Fernet y solo mostramos los primeros 6 caracteres para su identificación.

Rótelo desde SPA → Admin → Webhooks → Rotar secreto. Los receptores existentes rechazarán los eventos firmados hasta que se actualicen con el nuevo secreto: programe la rotación con una ventana de despliegue.

Disparo de prueba

Cada endpoint registrado tiene un botón «Test fire» en el admin de la SPA que envía un sobre webhook.test para que pueda verificar su receptor antes de pasar a producción. El sobre de prueba tiene la misma forma que un evento real, pero con un payload sintético etiquetado como "test": true en data.

Registro de entregas

SPA → Admin → Webhooks muestra las últimas 100 entregas por endpoint con el estado HTTP, los intentos, el último cuerpo de respuesta (truncado) y los sellos de tiempo. Filtre por estado / endpoint para depurar problemas del receptor.