Recibe eventos por webhook

Suscríbete a eventos del catálogo, verifica la firma y responde a tiempo.

GuíaCon aprobaciónClave secreta
Antes de empezar. Crear webhooks pide una clave secreta con el permiso webhooks:write, que se aprueba en soporte: pídelo desde Configuración › API Keys.

Crea la suscripción

La respuesta trae el secret con el que se firman las entregas. Se muestra una sola vez: guárdalo.

cURL
curl -X POST https://api.bydomu.com/v1/webhooks \
  -H "X-API-Key: $BYDOMU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://tu-servidor.com/webhooks/bydomu",
    "eventTypes": ["deal.won", "contact.*"],
    "description": "Negocios ganados y contactos"
  }'
Respuesta · 201 · ejemplo
{
  "data": { "id": "clx1whk001", "secret": "whsec_…" }
}

Verifica la firma

Cada entrega lleva X-Domu-Signature: t=…,v1=…: el HMAC-SHA256 de «timestamp.cuerpo» con tu secret. Usa el cuerpo crudo, compara en tiempo constante y rechaza marcas de tiempo viejas.

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

// header = X-Domu-Signature: t=<timestamp>,v1=<hmac>
function verifyWebhook(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const timestamp = Number(parts.t);
  if (!timestamp || !parts.v1) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSec) return false;
  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1);
  return a.length === b.length && timingSafeEqual(a, b);
}

Responde a tiempo

Hasta 5 intentos (0 s, 5 s, 30 s, 2 min y 10 min) ante error de red, 429 o 5xx. Responde 2xx en menos de 10 s.

El id de cada entrega es estable: úsalo para descartar las repetidas.

Entrega · ejemplo
{
  "id": "5f3a0c1e-7d2b-4f7e-9a51-0b6c1d2e3f40",
  "type": "deal.won",
  "timestamp": "2026-09-22T14:30:00.000Z",
  "organizationId": "clx1org001",
  "actor": { "kind": "API", "userId": null },
  "data": { … }
}