Configuración de webhooks

Guía paso a paso para registrar un endpoint de webhook de Certivant, guardar el secreto de firma, enviar un evento de prueba, rotar secretos y configurar excepciones por formulario.

Los webhooks permiten que Certivant envíe los cambios de estado a su backend en tiempo real. En lugar de consultar GET /requests/:id hasta que termina el procesamiento, Certivant hace una petición POST a una URL que usted controla cada vez que ocurre un evento de interés.

Esta página cubre la configuración única. Para la verificación de firma que debe implementar antes de pasar a producción, consulte Verificación de firma.

Lo que necesita

  • Una URL HTTPS accesible públicamente que acepte peticiones POST con un cuerpo JSON. Durante el desarrollo, localhost sirve si usa un túnel (ngrok, Cloudflare Tunnel, tailscale funnel).
  • El rol Propietario o Administrador en la organización de Certivant: los miembros no pueden cambiar la configuración de webhooks.
  • Un lugar seguro donde guardar secretos: recibirá un secreto de firma HMAC que debe conservar junto con el resto de sus credenciales de producción.

1 — Cree su endpoint

Un manejador mínimo tiene este aspecto (se muestra con Node + Hono; cualquier framework sirve):

app.post("/webhooks/certivant", async (c) => {
  const body = await c.req.text();   // Read RAW body — needed for signature check
  const signature = c.req.header("X-Certivant-Signature-V2");
  const payload = JSON.parse(body);

  // Connectivity ping (the dashboard "Test" button) — ack immediately.
  // It carries `test: true` and mutates nothing, so no signature is required.
  if (payload.test === true || payload.event === "kyc.webhook.test") {
    return c.json({ ok: true }, 200);
  }

  // Verify the signature BEFORE trusting a real event, and reject if it fails.
  // See /developer/webhooks/signature-verification for the verify helper
  // (checks `t=<unix>,v1=<hex>` over `${t}.${body}`, 300 s tolerance).
  if (!verifyCertivantSignature(body, signature, process.env.CERTIVANT_WEBHOOK_SECRET!)) {
    return c.json({ error: "invalid signature" }, 401);
  }

  // Acknowledge fast — Certivant will retry if you take > 10s
  c.executionCtx.waitUntil(handlePayload(payload));
  return c.json({ received: true }, 200);
});

Las dos reglas innegociables:

  1. Responda con 2xx en menos de 10 segundos. Certivant considera cualquier otra respuesta (5xx, 4xx, tiempo agotado, error de conexión) como un fallo de entrega y reintenta con retroceso exponencial.
  2. Lea el cuerpo sin procesar antes de analizar el JSON. La verificación de firma calcula el hash de la cadena exacta de bytes que envió Certivant. Si su framework analiza primero el JSON, regenerará una cadena distinta y la firma no coincidirá.

2 — Configure la URL en el panel

Inicie sesión en el panel de Certivant con una cuenta de Propietario o Administrador.
Vaya a KYC → Configuración → Webhooks.
Pegue la URL de su endpoint en URL del webhook, por ejemplo https://api.yourapp.com/webhooks/certivant. Solo HTTPS: el HTTP simple se rechaza.
Haga clic en Guardar. Certivant genera un secreto de firma en el primer guardado (visible solo una vez: cópielo en su entorno de inmediato).
El secreto tiene el prefijo whsec_. Guárdelo en su gestor de secretos como CERTIVANT_WEBHOOK_SECRET.

El secreto se muestra solo una vez, al generarlo o rotarlo: no hay ningún botón para «mostrar de nuevo el secreto», así que guárdelo de inmediato. Si lo pierde, rótelo (consulte más abajo) para obtener uno nuevo.

3 — Envíe un evento de prueba

Dos botones le ayudan a verificar la integración:

  • Probar (junto a la URL del webhook) envía un ping ligero de conectividad kyc.webhook.test que lleva test: true. Solo confirma que su endpoint es accesible y devuelve 2xx: no necesita datos de solicitud y funciona incluso antes de guardar un secreto de firma. Confírmelo de inmediato (consulte el manejador anterior).

  • Enviar un evento de prueba (KYC → Desarrollador → Eventos de webhook) le permite elegir el evento (el ping kyc.webhook.test o un payload de ejemplo kyc.request.created / approved / rejected / escalated) y lo envía POST firmado exactamente como una entrega real (X-Certivant-Signature-V2 más las cabeceras X-KYC-*, marca de tiempo Unix y su secreto de webhook). Los payloads de ejemplo llevan "test": true y un requestId falso. Úselo para:

  • Confirmar que la URL es accesible desde la infraestructura de Certivant.

  • Confirmar que su verificación de firma acepta una firma válida.

  • Ver la forma exacta del payload antes de que se disparen eventos reales.

También puede lanzar una prueba de forma programática, útil si quiere automatizar sus pruebas de integración:

curl -X POST https://app.certivant.com/api/kyc/settings/webhook-test \
  -H "Cookie: better-auth.session_token=..." \
  -H "Content-Type: application/json" \
  -d '{"event":"kyc.request.approved"}'
# returns { status: 200, latencyMs: 142, event, signed: true, headers: [...], responsePreview } if your endpoint replied

El cuerpo es opcional (por defecto, kyc.webhook.test). El endpoint usa una cookie de sesión, no una clave de API: es una acción del lado del panel.

4 — Rote el secreto de firma

Cuando un secreto queda expuesto (o una vez al año, como buena higiene):

Abra KYC → Configuración → Webhooks.
Haga clic en Rotar secreto. Certivant genera un nuevo valor whsec_… y lo muestra una sola vez.
Actualice su variable de entorno con el nuevo valor.
Despliegue. Tras el despliegue, el secreto antiguo deja de ser válido: los reintentos en vuelo que todavía lleven la firma antigua fallarán la verificación en su lado, y Certivant los tratará como no entregables.

No hay un periodo de solapamiento en el lado del emisor: las nuevas entregas se firman solo con el nuevo secreto. Las recetas de verificación de Verificación de firma aceptan una lista de secretos y varios valores v1=, así que puede desplegar un verificador que confíe tanto en el secreto antiguo como en el nuevo antes de rotar. Si no, rote durante un periodo de poca actividad y vigile sus registros en busca de fallos de verificación justo después.

Excepción de webhook a nivel de formulario

Las solicitudes KYC creadas a través de un formulario pueden sustituir la URL de webhook predeterminada de la organización por una URL específica del formulario. Configúrelo en la página de ajustes del formulario en el panel. Es útil cuando tiene varias integraciones que comparten la misma cuenta de Certivant: apunte cada formulario al equipo que lo gestiona.

El secreto de firma es compartido entre la URL predeterminada y las excepciones por formulario. La cabecera de firma es idéntica sea cual sea la URL que reciba el evento.

Lo que no genera webhooks

Algunas acciones no disparan webhooks:

  • La creación, revocación o cambio de ámbitos de una clave de API.
  • Los cambios de configuración (ediciones de marca blanca, ajustes de umbrales KYC).
  • Las descargas de documentos.
  • Los comentarios de revisión manual.

Si necesita reaccionar ante estos eventos, consulte en su lugar el Registro de actividad del panel: todavía no existe una API pública para ello.

Siguientes pasos

  • Verificación de firma: hágalo antes de pasar a producción. Sin ella, cualquiera puede falsificar peticiones a su URL de webhook.
  • Eventos: el catálogo completo de tipos de evento y payloads.
  • Reintentos: qué ocurre cuando su endpoint no está disponible.