Menu

Webhooks

O MB Suite avisa com um POST assinado quando algo acontece na sua organização: como assinar, verificar a assinatura e receber as novas tentativas.

Um webhook é uma assinatura: você escolhe os eventos e uma URL https:// pública, e cada vez que um acontece o MB Suite envia um POST com o evento assinado. Eles são criados e administrados em Configurações → API e MCP → Webhooks (owners e admins). Pela API e pelo MCP se leem as assinaturas, o catálogo de eventos e as entregas.

Criar uma assinatura

  1. 1Criar webhook: a URL do seu servidor, os eventos, o formato (Completo ou Somente IDs) e, num workspace, se escuta também as suas Contas.
  2. 2Em Avançado, até 5 cabeçalhos fixos se o seu receptor exige um token próprio (Make, Monday). Os valores ficam guardados cifrados e não aparecem de novo.
  3. 3Copie o segredo de assinatura (whsec_…): ele aparece uma única vez. Pode ser rotacionado; durante 24 horas assina-se com o novo e com o anterior.
  4. 4Enviar evento de teste envia um webhook.test assinado, mesmo com a assinatura desligada.

Cada organização tem um limite de assinaturas ativas conforme o plano, e nunca mais de 20. O destino tem que ser um servidor público: endereços privados, internos ou do MB Suite são recusados, e são revisados de novo antes de cada envio.

O que o seu servidor recebe

Um POST com Content-Type: application/json, um corpo de até 256 KB e estes cabeçalhos:

CabeçalhoValor
MB-Signaturet=<unix>,v1=<hex> (veja abaixo).
MB-Event-IdO id do evento (evt_…).
MB-Event-TypeO tipo, por exemplo crm.deal.stage_changed.
MB-Webhook-IdA assinatura.
MB-Delivery-IdA entrega (um reenvio manual cria outra).
MB-Api-VersionA versão com que o corpo foi montado.
Idempotency-KeyO id do evento: igual em todas as novas tentativas.
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 traz os registros inteiros, na versão da assinatura.
  • Somente IDs (thin): só ids e valores simples; o seu sistema consulta o resto pela API.
  • Um evento que não cabe em 256 KB é enviado como Somente IDs, com "truncated": true em data.

A lista completa de eventos, com um exemplo de cada, está em Eventos. Cada operação da referência diz quais eventos pode emitir; o que um evento ainda não cobre está na descrição dele.

Verificar a assinatura

MB-Signature é t=<unix>,v1=<hex>, com v1 = HMAC-SHA256(segredo, "<t>.<corpo>") sobre o corpo exato, sem serializá-lo de novo. Durante uma rotação chegam dois v1=: vale qualquer um. Recuse um t de mais de 5 minutos (replay) e compare em tempo 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();
// O corpo cru: express.raw, NÃO express.json (re-serializar muda a assinatura).
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 }
  // Idempotência: `event.id` (também vem como `Idempotency-Key`) se repete quando reenviamos.
  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); // qualquer 2xx = entregue; outra coisa ou mais de 10 s = nova tentativa
});

Responder e novas tentativas

  • Responda 2xx em menos de 10 segundos e deixe o trabalho pesado para uma fila. Qualquer outra resposta, um redirecionamento (3xx) ou o silêncio contam como falha.
  • Novas tentativas: na hora, depois de 5 minutos, de 30, de 2 horas, de 5, de 10 e depois a cada 12 horas: 11 tentativas em cerca de 72 horas.
  • Uma nova tentativa traz o mesmo id de evento: use-o para não processar duas vezes.
  • Depois de 24 horas de falhas seguidas, os owners e admins recebem um aviso por e-mail; às 72 horas a assinatura se desliga sozinha. Ao reativá-la você pode reenviar o que falhou nas 72 horas anteriores, e cada entrega pode ser reenviada à mão em Ver entregas.
  • Eventos e entregas são guardados por 30 dias.

Receitas: Make, Odoo e Monday

Make

  1. 1No Make, crie um cenário que comece com Webhooks → Custom webhook e copie a URL (https://hook.us1.make.com/…).
  2. 2No MB Suite, Criar webhook com essa URL e os eventos que quiser (por exemplo crm.lead.created e crm.deal.stage_changed).
  3. 3No Make, Re-determine data structure; no MB Suite, Enviar evento de teste (ou uma mudança real) para o Make aprender a forma do JSON.
  4. 4O Make não verifica HMAC: adicione um cabeçalho fixo (X-Make-Token: <um valor longo>) e compare-o num Filter do cenário.

Odoo

O Odoo 17 ou posterior tem regras de automação com o gatilho On webhook: cada regra dá uma URL própria (https://<seu-odoo>/web/hook/<uuid>) e uma ação Executar código Python lê payload (o evento inteiro). Como essa ação não vê o corpo cru, proteja-a com um cabeçalho fixo e guarde payload["id"] para não criar o lead duas vezes numa nova tentativa. Em versões anteriores, coloque o Make no meio com Odoo → Create a Record.

Monday

O Monday não recebe webhooks de outros sistemas: o mais simples é o Make no meio (Custom webhook → Monday → Create an Item), mapeando data.person.full_name, data.deal.title, data.stage.name ou data.source.name. Para não duplicar itens numa nova tentativa, filtre pelo id do evento ou busque o item por data.deal.id antes de criá-lo.