Ir para o conteúdo
WazGoDOCS
Documentação

WAZGO PUBLIC API · V1

Webhooks

Eventos suportados nesta versão:

EventoQuandoDados públicos
campaign.sentUma entrega de campanha foi marcada como enviada.deliveryId, campaignId, groupId, sentAt
campaign.failedUma entrega de campanha falhou.deliveryId, campaignId, groupId, failedAt
group.syncedUm snapshot persistido de grupos foi sincronizado.syncId, groupsFound, created, updated
webhook.testEvento sintético enviado pelo painel.test: true

Envelope

{
  "id": "evt_exemplo",
  "type": "campaign.sent",
  "version": "1",
  "createdAt": "2026-10-02T12:00:00.000Z",
  "workspaceId": "workspace_exemplo",
  "data": {
    "deliveryId": "delivery_exemplo",
    "campaignId": "campaign_exemplo",
    "groupId": "group_exemplo",
    "sentAt": "2026-10-02T12:00:00.000Z"
  }
}

Validar assinatura

O header X-Wazbot-Signature contém v1= seguido do HMAC-SHA256 hexadecimal minúsculo de timestamp + "." + rawBody. O timestamp em Unix seconds está em X-Wazbot-Timestamp. Valide os bytes originais, compare em tempo constante e rejeite timestamps com mais de cinco minutos.

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

const app = express();
app.post("/webhooks/wazgo", express.raw({ type: "application/json" }), (req, res) => {
  const secret = process.env.WAZGO_WEBHOOK_SECRET;
  const timestamp = req.header("X-Wazbot-Timestamp");
  const signature = req.header("X-Wazbot-Signature")?.replace(/^v1=/, "");
  if (!secret || !timestamp || !signature || !Buffer.isBuffer(req.body)) return res.sendStatus(400);
  const sentAt = Number(timestamp);
  if (!Number.isInteger(sentAt) || Math.abs(Date.now() / 1000 - sentAt) > 300) return res.sendStatus(400);
  const expected = crypto.createHmac("sha256", secret).update(timestamp + ".").update(req.body).digest();
  const received = Buffer.from(signature, "hex");
  if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) return res.sendStatus(401);
  const event = JSON.parse(req.body.toString("utf8"));
  // Deduplicate event.id and enqueue the work before acknowledging.
  return res.sendStatus(204);
});

Entrega, tentativas e replay

  • Qualquer resposta HTTP 2xx confirma a entrega.
  • A semântica é at-least-once: um evento pode chegar mais de uma vez; deduplique pelo campo id.
  • Falhas temporárias, timeout e HTTP 408/425/429/5xx podem ser repetidos. As tentativas são limitadas; atrasos exatos não são um contrato público.
  • Não há garantia de ordem global. Reconcile o estado atual pela API quando necessário.
  • O painel permite reenviar entregas elegíveis; o eventId original permanece e a requisição recebe novo timestamp e assinatura.

Use HTTPS. Configure o servidor para capturar o body bruto antes de qualquer parser JSON. Faça a deduplicação e enfileire seu trabalho antes de responder 2xx.