Menú

Webhooks

MB Suite te avisa con un POST firmado cuando algo pasa en tu organización: cómo suscribirte, verificar la firma y recibir los reintentos.

Un webhook es una suscripción: eliges los eventos y una URL https:// pública, y cada vez que uno ocurre MB Suite manda un POST con el evento firmado. Se crean y administran en Configuración → API y MCP → Webhooks (owners y admins). Por la API y el MCP se leen las suscripciones, el catálogo de eventos y las entregas.

Crear una suscripción

  1. 1Crear webhook: la URL de tu servidor, los eventos, el formato (Completo o Solo IDs) y, en un workspace, si escucha también a sus Cuentas.
  2. 2En Avanzado, hasta 5 encabezados fijos si tu receptor exige un token propio (Make, Monday). Sus valores se guardan cifrados y no se vuelven a mostrar.
  3. 3Copia el secreto de firma (whsec_…): se muestra una sola vez. Se puede rotar; durante 24 horas se firma con el nuevo y con el anterior.
  4. 4Enviar evento de prueba manda un webhook.test firmado, aunque la suscripción esté apagada.

Cada organización tiene un tope de suscripciones activas según su plan, y nunca más de 20. El destino tiene que ser un servidor público: las direcciones privadas, internas o de MB Suite se rechazan, y se vuelven a revisar antes de cada envío.

Qué recibe tu servidor

Un POST con Content-Type: application/json, un cuerpo de hasta 256 KB y estos encabezados:

EncabezadoValor
MB-Signaturet=<unix>,v1=<hex> (ver abajo).
MB-Event-IdEl id del evento (evt_…).
MB-Event-TypeEl tipo, por ejemplo crm.deal.stage_changed.
MB-Webhook-IdLa suscripción.
MB-Delivery-IdLa entrega (un reenvío manual crea otra).
MB-Api-VersionLa versión con la que se armó el cuerpo.
Idempotency-KeyEl id del evento: igual en todos los reintentos.
User-AgentMB-Suite-Webhooks/1.0 (+https://developers.mb-suite.com/webhooks)
{
  "id": "evt_4f9c1a7e2b6d0c3a8e5f1b9d2c",
  "type": "crm.deal.stage_changed",
  "created_at": "2025-11-01T12:26:40.000Z",
  "api_version": "2026-11-01",
  "org_id": "ORG_ID",
  "data": { "…": "…" }
}
  • Completo (snapshot, recomendado): data trae los registros enteros, en la versión de la suscripción.
  • Solo IDs (thin): solo ids y valores simples; tu sistema consulta el resto por la API.
  • Un evento que no entra en 256 KB se manda como Solo IDs, con "truncated": true en data.

La lista completa de eventos, con un ejemplo de cada uno, está en Eventos. Cada operación de la referencia dice qué eventos puede emitir; lo que un evento todavía no cubre lo dice su descripción.

Verificar la firma

MB-Signature es t=<unix>,v1=<hex>, con v1 = HMAC-SHA256(secreto, "<t>.<cuerpo>") sobre el cuerpo exacto, sin volver a serializarlo. Durante una rotación llegan dos v1=: vale cualquiera. Rechaza un t de más de 5 minutos (replay) y compara en tiempo constante.

import crypto from "node:crypto";
import express from "express";

function verifyMbSignature(header, rawBody, secret, toleranceSec = 300) {
  if (!header) return false;
  const parts = header.split(",").map((p) => p.trim().split("="));
  const t = Number(parts.find(([k]) => k === "t")?.[1]);
  const signatures = parts.filter(([k]) => k === "v1").map(([, v]) => v);
  if (!t || signatures.length === 0) return false;
  if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSec) return false; // replay
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return signatures.some((sig) => sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)));
}

const app = express();
// El cuerpo crudo: express.raw, NO express.json (re-serializar cambia la firma).
app.post("/mb-suite/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!verifyMbSignature(req.get("MB-Signature"), req.body, process.env.MB_WEBHOOK_SECRET)) {
    return res.sendStatus(400);
  }
  const event = JSON.parse(req.body);
  // event = { id, type, created_at, api_version, org_id, data }
  // Idempotencia: `event.id` (también viene como `Idempotency-Key`) se repite si reintentamos.
  switch (event.type) {
    case "crm.lead.created":
      // event.data.person, event.data.prospect | event.data.deal, event.data.source
      break;
    case "crm.deal.stage_changed":
      // event.data.deal, event.data.stage, event.data.previous.stage
      break;
  }
  res.sendStatus(200); // cualquier 2xx = entregado; otra cosa o más de 10 s = reintento
});

Responder y reintentos

  • Responde 2xx en menos de 10 segundos y deja el trabajo pesado para una cola. Cualquier otra respuesta, una redirección (3xx) o el silencio cuentan como falla.
  • Reintentos: al instante, a los 5 minutos, a los 30, a las 2 horas, a las 5, a las 10 y después cada 12 horas: 11 intentos en unas 72 horas.
  • Un reintento trae el mismo id de evento: úsalo para no procesar dos veces.
  • Después de 24 horas de fallas seguidas, los owners y admins reciben un aviso por correo; a las 72 horas la suscripción se apaga sola. Al reactivarla puedes reenviar lo que falló en las 72 horas anteriores, y cada entrega se puede reenviar a mano desde Ver entregas.
  • Eventos y entregas se guardan 30 días.

Recetas: Make, Odoo y Monday

Make

  1. 1En Make, crea un escenario que arranque con Webhooks → Custom webhook y copia su URL (https://hook.us1.make.com/…).
  2. 2En MB Suite, Crear webhook con esa URL y los eventos que quieras (por ejemplo crm.lead.created y crm.deal.stage_changed).
  3. 3En Make, Re-determine data structure; en MB Suite, Enviar evento de prueba (o un cambio real) para que Make aprenda la forma del JSON.
  4. 4Make no verifica HMAC: agrega un encabezado fijo (X-Make-Token: <un valor largo>) y compáralo en un Filter del escenario.

Odoo

Odoo 17 o posterior tiene reglas de automatización con el disparador On webhook: cada regla da una URL propia (https://<tu-odoo>/web/hook/<uuid>) y una acción Ejecutar código Python lee payload (el evento entero). Como esa acción no ve el cuerpo crudo, protégela con un encabezado fijo y guarda payload["id"] para no crear el lead dos veces en un reintento. En versiones anteriores, pon Make en el medio con Odoo → Create a Record.

Monday

Monday no recibe webhooks de otros sistemas: lo más simple es Make en el medio (Custom webhook → Monday → Create an Item), mapeando data.person.full_name, data.deal.title, data.stage.name o data.source.name. Para no duplicar ítems en un reintento, filtra por el id del evento o busca el ítem por data.deal.id antes de crearlo.