ZAP-API
PreçosCasos de UsoBlogDocsLogin
Começar grátis
  1. Blog
  2. Console de webhooks com replay: debug em produção sem logs manuais
Tutorial

Console de webhooks com replay: debug em produção sem logs manuais

Use o console de webhooks da ZAP-API para inspecionar entregas, ver payloads completos, re-enviar eventos com falha e diagnosticar integrações sem acesso ao servidor.

17 de maio de 2026·12 min de leitura·Equipe Editorial ZAP-API
Console de webhooks com replay: debug em produção sem logs manuais

É 2h da manhã. Cliente liga: "as confirmações de pedido pararam de chegar no WhatsApp dos meus clientes". Você abre o terminal, faz tail -f nos logs do servidor, procura "webhook" no meio do barulho, encontra alguns 500 misturados com 200 — mas qual deu errado? Para qual cliente? Foi nosso bug ou bug do servidor dele?

Para isso a ZAP-API guarda o histórico de cada entrega de webhook da sua instância: para onde foi, qual evento, o que o seu servidor respondeu, em que tentativa está e quando sai a próxima. E o que falhou pode ser reenviado pela API, com o token da instância, ou pelo painel.

O que fica registrado em cada entrega

  • ID da entrega (número, ex.: 48213) — é ele que você usa para reenviar
  • URL de destino no momento da entrega
  • Tipo do evento (message.received, message.status, instance.connected…)
  • Status HTTP que o seu servidor respondeu, ou vazio quando não houve resposta
  • Mensagem de erro da última tentativa que falhou (ex.: Request failed with status code 500, timeout of 5000ms exceeded) — pode continuar preenchida mesmo depois de uma tentativa bem-sucedida
  • Tentativa atual e o máximo (6)
  • Próxima tentativa agendada, ou vazio quando não há mais

Como funciona o retry

Cada evento tem até 6 tentativas: a primeira imediata e as seguintes depois de 1min, 5min, 15min, 1h, 6h — cerca de 7 horas no total, com variação aleatória de até 20% em cada espera. Conta como falha: resposta de erro (5xx, 403, 404, 429…), redirecionamento ou nenhuma resposta em 5 segundos.

Três respostas encerram na hora, sem retry: 400, 401 e 410. O 410 também remove a URL da instância, porque é o seu servidor dizendo que o endpoint não existe mais.

Esgotadas as tentativas, a entrega fica guardada para você reenviar — até 90 dias contados da criação do evento. Entregas bem-sucedidas ficam 30 dias no histórico.

Tentativas e reenvios podem chegar fora de ordem em relação a eventos mais novos, e o timestamp do corpo é sempre o do evento original. Ordene pelo timestamp e não rejeite um evento só por ser antigo.

Consultando o histórico via API

curl "https://api.zap-api.tech/v1/instances/SEU_INSTANCE_ID/webhook/logs?limit=50&offset=0" \
  -H "Authorization: Bearer tk_seu_token"

Resposta (mais recentes primeiro):

{
  "logs": [
    {
      "id": 48213,
      "event": "message.received",
      "url": "https://meusite.com.br/webhooks/zap",
      "statusCode": 500,
      "errorMessage": "Request failed with status code 500",
      "delivered": false,
      "attempt": 3,
      "maxAttempts": 6,
      "nextRetryAt": "2026-05-15T03:52:00Z",
      "createdAt": "2026-05-15T03:30:11Z"
    }
  ],
  "total": 47,
  "limit": 50,
  "offset": 0
}

O limit vai até 100. Para um resumo do período (total, entregues, falhas, taxa de sucesso e a última entrega), use GET /v1/instances/SEU_INSTANCE_ID/webhook/stats?days=7 (máximo 30).

Reenviando uma entrega

Depois de corrigir o problema no seu servidor, reenvie o que falhou:

curl -X POST "https://api.zap-api.tech/v1/instances/SEU_INSTANCE_ID/webhook/deliveries/48213/replay" \
  -H "Authorization: Bearer tk_seu_token"
  • O reenvio aceita entregas que não chegaram e não estão em andamento. Entrega já entregue, ou com menos de 5 minutos e sem nova tentativa agendada, responde 422.
  • O reenvio reaproveita a mesma entrega e o mesmo X-Zap-Event-Id — o seu deduplicador reconhece o evento — e recomeça as tentativas.
  • Se você trocou a URL do webhook, o reenvio vai para a URL configurada agora.
  • Webhook pausado: 409 WEBHOOK_PAUSED — reative-o no painel primeiro. Instância sem URL (por exemplo, depois de um 410): 409 NO_WEBHOOK_URL.
  • Só entregas da própria instância do token: id de outra instância responde 404.

Script de reenvio em lote

Cenário comum: seu servidor ficou fora do ar por algumas horas e parte das entregas esgotou as tentativas. Este script percorre o histórico e reenvia as que não chegaram:

// reenviar-falhas.js
const axios = require("axios");

const INSTANCE = process.env.ZAP_INSTANCE_ID;
const ZAP = axios.create({
  baseURL: "https://api.zap-api.tech/v1/instances/" + INSTANCE,
  headers: { Authorization: "Bearer " + process.env.ZAP_TOKEN },
});

async function reenviarFalhas(desdeIso) {
  const desde = new Date(desdeIso).getTime();
  let offset = 0;
  let total = 0;

  while (true) {
    const { data } = await ZAP.get("/webhook/logs", { params: { limit: 100, offset } });
    if (data.logs.length === 0) break;

    for (const e of data.logs) {
      if (new Date(e.createdAt).getTime() < desde) return console.log("Reenviadas: " + total);
      // não chegou, nada agendado e com mais de 5 min (as mais novas ainda podem estar saindo)
      const esgotou = !e.delivered && e.nextRetryAt === null
        && Date.now() - new Date(e.createdAt).getTime() > 5 * 60 * 1000;
      if (!esgotou) continue;
      try {
        await ZAP.post("/webhook/deliveries/" + e.id + "/replay");
        total++;
      } catch (err) {
        const status = err.response ? err.response.status : null;
        if (status === 409) return console.error("Webhook pausado ou sem URL: resolva no painel e rode de novo.");
        console.error("erro " + e.id + ": " + (status || err.message));
      }
      await new Promise((r) => setTimeout(r, 200)); // não estoure o limite da API
    }
    offset += data.logs.length;
  }
  console.log("Reenviadas: " + total);
}

reenviarFalhas("2026-05-15T00:00:00Z");

Validação da assinatura no seu endpoint

Toda entrega leva o header X-ZapAPI-Signature-256 no formato sha256=<hex>, calculado sobre o corpo bruto com o secret do webhook. O secret é gerado na primeira configuração da URL (ou quando você envia "secret": true para trocá-lo) e aparece uma única vez na resposta; você também pode definir o seu. Valide a assinatura para garantir que a requisição veio da ZAP-API:

const crypto = require("crypto");
const express = require("express");

const app = express();
const SECRET = process.env.ZAP_WEBHOOK_SECRET;

// IMPORTANTE: corpo bruto antes do JSON parser
app.post("/webhooks/zap", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-zapapi-signature-256"] || "";
  const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");

  const a = Buffer.from(signature);
  const b = Buffer.from(expected);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send("invalid signature");
  }

  const evento = JSON.parse(req.body.toString()); // { event, instanceId, timestamp, data }
  res.status(200).send("ok"); // responda rápido; processe depois
});

Outros headers de cada entrega: X-Zap-Event-Id (igual em todas as tentativas e no reenvio — use para deduplicar), X-Zap-Instance e X-Zap-Timestamp. Quem configurou um secret recebe também o header antigo X-Zap-Signature, mantido por compatibilidade.

Casos práticos

Caso 1: bug que só apareceu em produção

Algumas confirmações de pedido não chegam. No histórico você vê entregas de message.status com statusCode: 500, descobre no seu log o erro num campo opcional, corrige e reenvia as que esgotaram as tentativas. Se o conserto saiu em menos de 7 horas, a maioria nem precisou de reenvio: o próprio retry entregou.

Caso 2: mudança de URL do webhook

O time migra o backend de servidor e a URL muda. Atualize a URL no painel ou com PUT /v1/instances/:id/webhook. As entregas novas vão para a URL nova. As que falharam na URL antiga param de ser re-tentadas automaticamente; reenvie-as manualmente e elas vão para a URL nova.

FAQ

Quanto tempo as entregas ficam guardadas?

Entregas bem-sucedidas: 30 dias. Entregas que não chegaram: 90 dias. Depois disso são apagadas. Para guardar por mais tempo, grave os eventos do seu lado ao recebê-los.

O reenvio duplica o evento?

O evento chega de novo ao seu endpoint, com o mesmo X-Zap-Event-Id. Desenhe seu handler para ser idempotente: se já processou aquele id, responda 200 e ignore.

Diferença entre 5xx e timeout?

5xx é o seu servidor respondendo com erro. Timeout é não responder em 5 segundos. Os dois contam como falha e disparam retry. No histórico, o timeout aparece sem statusCode e com a mensagem de erro do tempo esgotado.

E se o meu endpoint falhar por muito tempo?

Se, numa janela de 6 horas, o endpoint não tiver nenhum sucesso e acumular pelo menos 50 respostas 3xx, 400, 401, 403, 404, 410 ou 429, ou erros de conexão por mais de uma hora, o webhook da instância é pausado e você recebe um aviso por e-mail. Erros 5xx não pausam (eles seguem o retry normal). Durante a pausa guardamos até 5.000 eventos por instância — os seguintes são descartados. Para despausar, reative no painel ou configure uma URL nova; depois reenvie o que ficou guardado.

Próximo passo

Criar conta grátis e teste a integração com histórico e reenvio desde o primeiro dia.

Experimente a ZAP-API gratuitamente

7 dias de trial sem precisar de cartão. A partir de R$29/mês*.

Criar instância grátis
EE
Equipe Editorial ZAP-APIRevisão técnica

Desenvolvedores e especialistas em integrações WhatsApp. Todo conteúdo passa por revisão técnica para garantir precisão e aplicabilidade.

Ver perfil completoDocumentaçãoTrial grátis

Leia também

Tutorial · 29 de jun. de 2026 · 8 min

Como integrar Webhook do WhatsApp em Node.js

Guia completo para integrar webhooks WhatsApp em Node.js. Passo a passo com código pronto. Comece grátis na ZAP API.

Tutorial · 30 de abr. de 2026 · 11 min

Webhook WhatsApp seguro: HMAC, retry exponencial e DLQ

Como usar webhook WhatsApp em produção com assinatura HMAC-SHA256, retry com backoff exponencial e Dead Letter Queue. Exemplos em Node.js.

Tutorial · 06 de jun. de 2026 · 9 min

Disparo de mensagens em massa no WhatsApp: como fazer sem ser banido (2026)

Throttling, opt-out automático, personalização por destinatário e controle de volume: as 5 regras para campanhas em massa sem risco de banimento. Código pronto para produção.

Tutorial · 07 de mar. de 2026 · 11 min

Como enviar mensagem WhatsApp via API em Java

Integre WhatsApp ao Java com HttpClient nativo ou Spring Boot. Envie mensagens, receba webhooks e implemente notificações automáticas.

Tópicos:Chatbots com IAE-commerceAPI WhatsApp

Explore também

API WhatsApp grátisTeste 7 dias, sem cartãoAutomação WhatsAppAutomatize via REST APIAPI não oficialSem aprovação da MetaCasos de usoWhatsApp API por segmentoComparativoZAP-API vs alternativasPreçosPlanos e o que está inclusoGlossárioTermos técnicos de WhatsApp API
ZAP-API

API REST para WhatsApp com webhooks assinados, Meta Pixel/CAPI e compliance LGPD. Sem aprovação da Meta.

Status operacional🇧🇷 Feito no Brasil

Produto

  • Preços
  • Casos de uso
  • Automação WhatsApp
  • API não oficial
  • Comparativo
  • API WhatsApp grátis
  • Dashboard

Recursos

  • Documentação
  • Blog
  • Glossário
  • RSS Feed

Empresa

  • Sobre
  • Imprensa
  • Termos de uso
  • Privacidade
  • Criar conta
  • Login

Contato

  • [email protected]
  • [email protected]
  • Resposta em até 24h úteis
© 2026 ZAP-API — Todos os direitos reservados·CNPJ 42.130.949/0001-56·Termos·Privacidade

Desenvolvido por PreviusIA