Enviar alertas para um webhook

5 min de leitura175
Copiar para a I.A.:

Além de e-mail e Slack, um alerta pode chamar um endereço do seu próprio sistema. É por aí que você abre um chamado automaticamente, grava o evento no seu banco ou dispara um fluxo no Zapier, Make ou n8n — todos aceitam receber um webhook, sem integração dedicada. O exemplo deste artigo é o alerta "NPS crítico" da pesquisa pós-atendimento.

Como configurar

  1. Em Alertas, clique em Novo Alerta (ou edite um existente). Só o administrador da conta cadastra alertas.
  2. Preencha Nome do Alerta, Condição e Pesquisa, como em qualquer alerta.
  3. Em Métodos de Notificação, ligue Webhook e informe a URL do endpoint.
  4. Salve e abra o alerta de novo em edição: aparece a Chave de assinatura (começa com whsec_), com o botão Copiar. Guarde-a no seu sistema — é com ela que você confirma que a chamada veio de nós.

Requisitos da URL

  • Precisa usar HTTPS e ter no máximo 255 caracteres.
  • Precisa ser acessível pela internet. Endereços internos (localhost, 192.168.x.x, 10.x.x.x, domínios .local) são recusados ao salvar.
  • Não siga com redirecionamento: a chamada vai só para o endereço informado, e uma resposta de redirecionamento conta como falha.

O que enviamos

Um POST com os cabeçalhos Content-Type: application/json e Signature, e um corpo neste formato:

{ "event": "alert.triggered", "alert": { "id": "12", "name": "NPS crítico", "condition": "nps_below", "threshold": 30 }, "survey": { "id": "01J9Z3K8TQ4M2X7V5B6N0P1R2S", "title": "Pós-atendimento" }, "context": { "current_nps": "12", "threshold": "30", "window": "Últimos 30 dias", "responses": "48" }, "triggered_at": "2026-07-27T15:34:56+00:00" }
  • event é sempre alert.triggered.
  • condition é um código estável, não um texto traduzido: nps_below, nps_above, sentiment_negative, no_response, response_rate_below, new_feedback ou question_average_below. Pode usá-lo num switch.
  • alert.threshold é número inteiro, ou null nas condições sem valor.
  • survey traz a pesquisa que disparou. Num alerta para todas as pesquisas, é a primeira que atendeu à condição.
  • triggered_at vem em ISO 8601 com o deslocamento de fuso — leia o deslocamento em vez de presumir o horário.

As chaves de context

Todos os valores de context são texto (string). As chaves mudam conforme a condição:

  • nps_below e nps_above: current_nps, threshold, window, responses.
  • question_average_below: question (o texto da pergunta), current_average (com uma casa decimal, como "2.4"), threshold, window, responses.
  • sentiment_negative: count, latest_comment (até 180 caracteres), window.
  • no_response: last_response (data no formato AAAA-MM-DD), days_since (∞ se nunca houve resposta), threshold.
  • response_rate_below: current_rate e threshold (com o símbolo %, como "12.5%"), sent, responses.
  • new_feedback: comment (até 200 caracteres), score (nota e máximo da escala, como "4/10"; não vem quando a resposta não tem nota, como num questionário sem pergunta que conte no NPS), when (data e hora, sem fuso).

Atenção: condition e as chaves de context são códigos estáveis, mas alguns valores saem como texto no idioma do dono da conta — window, latest_comment quando não há comentário e last_response quando a pesquisa nunca recebeu resposta. Não compare esses valores como se fossem código — para decidir, use condition.

Verificando a assinatura

O cabeçalho Signature é o HMAC-SHA256, em hexadecimal, do corpo da requisição usando a sua chave de assinatura. Calcule sobre o corpo bruto, exatamente como chegou — se você decodificar o JSON e codificar de novo, acentos e barras mudam de forma e a assinatura não bate. Confira antes de agir sobre o conteúdo: sem isso, quem descobrir a sua URL consegue forjar um alerta.

Em PHP:

$corpoBruto = file_get_contents('php://input'); $esperado = hash_hmac('sha256', $corpoBruto, $suaChave); if (! hash_equals($esperado, $_SERVER['HTTP_SIGNATURE'] ?? '')) { http_response_code(403); exit; }

Em Node.js (com o corpo bruto em rawBody):

const esperado = crypto.createHmac('sha256', suaChave).update(rawBody).digest('hex'); const recebido = req.get('Signature') || ''; const valido = recebido.length === esperado.length && crypto.timingSafeEqual(Buffer.from(recebido), Buffer.from(esperado));

Quando chega e novas tentativas

O webhook segue o ritmo de qualquer alerta: as condições são verificadas a cada 30 minutos e, depois de disparar, o mesmo alerta fica 6 horas sem chamar de novo.

Qualquer resposta 2xx conta como entregue. Cada chamada tem 5 segundos de limite; se o seu endpoint demorar, der erro ou redirecionar, fazemos até 3 tentativas no total, com espera crescente entre elas. Responda rápido (um 200 imediato) e processe depois, em segundo plano. Se as três falharem, o card do alerta mostra Última entrega falhou; passe o mouse sobre a marca para ver o destino e o motivo (por exemplo, Webhook: HTTP 500). O aviso some sozinho quando uma entrega seguinte ao webhook dá certo; uma entrega bem-sucedida no Slack não apaga a falha do webhook, e vice-versa.

Não há botão de envio de teste. Para ver uma chamada de verdade, crie um alerta Sem resposta por com valor 1 numa pesquisa que não recebeu respostas no último dia: ele dispara na próxima verificação.

Privacidade

O payload não identifica quem respondeu: o comentário e a nota vão, o nome e o e-mail não. Em pesquisa anônima, essa é uma promessa feita ao respondente, e ela vale também aqui.

Trocando a URL ou removendo

Trocar o endereço mantém a mesma chave de assinatura, então você não precisa reconfigurar a verificação do outro lado. Já desligar Webhook remove a URL e apaga a chave — se voltar a ligá-lo depois, uma chave nova é gerada.

Para onde ir depois

  • Alertas — as condições e com que frequência cada uma avisa.
  • Receber alertas no Slack — o mesmo aviso no canal do time.

Resumindo: ligue Webhook no alerta, informe uma URL HTTPS pública, guarde a chave de assinatura e valide o cabeçalho Signature sobre o corpo bruto antes de agir.

Este artigo foi útil?