1. Documentação
  2. Guias
  3. Webhooks
Ir para Dashboard
  • Documentação do Pushwi
  • Início rápido
  • Instalação do SDK
  • Referência do SDK
  • Soft-ask
  • Migração de outro provedor
  • Identificação de usuários
  • Segmentos
  • Campanhas
  • Descadastro e LGPD
  • Webhooks

Webhooks

Receba no seu servidor avisos de novos assinantes, descadastros e do resultado das campanhas, com assinatura HMAC.

Loading documentation…

Descadastro e LGPD< Previous

Powered by heyo

On this page

ConfigurandoEventosFormatosubscriber.createdsubscriber.unsubscribedcampaign.sentcampaign.failedVerificando a assinaturaEntregas e novas tentativas

O Pushwi pode avisar o seu sistema quando algo acontece no site, com um POST para uma URL que você define. Cada site tem um endereço de webhook e escolhe quais eventos quer receber.

Configurando

Em Desenvolvedor › Webhooks no painel:

  1. informe a URL de destino, http ou https;
  2. marque os eventos;
  3. gere o segredo de assinatura e guarde. Ele aparece uma única vez, e gerar outro invalida o anterior.

Sem URL ou sem segredo, nada é enviado. Endereços que apontam para a rede interna (localhost, IPs privados) são recusados. Para testar localmente, use um túnel como o cloudflared ou o ngrok.

Eventos

EventoQuando
subscriber.createdUm dispositivo novo se inscreveu
subscriber.unsubscribedUm dispositivo ou um assinante foi descadastrado
campaign.sentUma campanha terminou de sair
campaign.failedUma campanha não pôde ser enviada

Cliques e entregas individuais não geram webhook. Esses números ficam nos relatórios do painel.

Formato

Todo webhook é um POST com Content-Type: application/json e este envelope:

json
{  "event": "campaign.sent",  "sent_at": "2026-10-06T15:04:12+00:00",  "data": { }}

subscriber.created

json
{  "event": "subscriber.created",  "sent_at": "2026-10-06T15:04:12+00:00",  "data": {    "subscriber_id": "0199b2d4-6f1e-7c3a-9b1e-2f4a8c6d0e11",    "external_id": "user-42",    "subscription_id": 98231  }}

Disparado só quando o endpoint é novo para o site. A reinscrição de um navegador já conhecido não gera evento. external_id vem null para assinantes anônimos. Um assinante que já existia pode aparecer de novo quando inscreve outro aparelho, então trate subscriber_id como chave e não duplique registros.

subscriber.unsubscribed

json
{  "event": "subscriber.unsubscribed",  "sent_at": "2026-10-06T15:04:12+00:00",  "data": {    "subscriber_id": "0199b2d4-6f1e-7c3a-9b1e-2f4a8c6d0e11",    "external_id": "user-42",    "subscription_id": 98231  }}

Disparado em dois casos:

Origemsubscription_id
O navegador cancelou a inscrição pelo SDK (pushwi("unsubscribe"))O dispositivo que saiu
Alguém descadastrou o assinante inteiro pelo painelnull, porque todos os dispositivos dele saíram de uma vez

O evento sai uma vez por descadastro: cancelar de novo um dispositivo que já estava descadastrado não gera outro. O assinante pode continuar com outros aparelhos ativos, então não trate o evento como "a pessoa saiu de tudo" quando subscription_id vier preenchido.

Dispositivos que expiram (o serviço de push recusou a inscrição) e assinantes apagados por Excluir assinante não geram este evento.

campaign.sent

json
{  "event": "campaign.sent",  "sent_at": "2026-10-06T15:20:40+00:00",  "data": {    "campaign_id": 1287,    "campaign_name": "Frete grátis só hoje",    "recipient_count": 18430,    "send_limit_reached": false  }}
CampoQuando aparece
recipient_countQuantos dispositivos estavam no público do envio. 0 quando o público estava vazio.
send_limit_reachedtrue quando o limite de envios do plano cortou a campanha no meio
winner_variant_idEm teste A/B de duas fases, no aviso enviado depois do vencedor. Esse aviso não traz recipient_count.
incompletetrue quando o envio travou e o Pushwi encerrou a campanha com o que já tinha saído

Campanhas recorrentes geram um campaign.sent a cada envio, cada um com o campaign_id da cópia.

campaign.failed

json
{  "event": "campaign.failed",  "sent_at": "2026-10-06T15:20:40+00:00",  "data": {    "campaign_id": 1287,    "campaign_name": "Frete grátis só hoje",    "reason": "plan_limit_exceeded"  }}
reasonSignificado
plan_limit_exceededO limite de envios do mês acabou
service_interruptedA organização está suspensa
dispatch_failedErro ao montar o envio
nothing_was_deliveredNenhum dispositivo aceitou a notificação
ab_test_phase_one_delivered_nothingA primeira fase do teste A/B não entregou nada, então não houve vencedor
stuck_while_queuing, stuck_while_sendingO envio parou de avançar e foi encerrado

Verificando a assinatura

Cada chamada traz o cabeçalho Signature: o HMAC-SHA256, em hexadecimal, do corpo da requisição exatamente como chegou, usando o segredo do webhook como chave. Calcule sobre o corpo bruto, antes de qualquer parse de JSON. Reserializar o JSON pode mudar espaços ou escapes e quebrar a comparação.

import express from "express";import { createHmac, timingSafeEqual } from "node:crypto";const app = express();app.post("/webhooks/pushwi", express.raw({ type: "application/json" }), (req, res) => {const esperado = createHmac("sha256", process.env.PUSHWI_WEBHOOK_SECRET)  .update(req.body)  .digest("hex");const recebido = req.get("Signature") ?? "";if (recebido.length !== esperado.length ||    !timingSafeEqual(Buffer.from(recebido), Buffer.from(esperado))) {  return res.sendStatus(401);}const { event, data } = JSON.parse(req.body);// processe o evento…res.sendStatus(204);});

O envelope não tem timestamp assinado. Se quiser recusar reenvios antigos, compare sent_at com a hora atual depois de validar a assinatura.

Entregas e novas tentativas

O Pushwi espera até 3 segundos por uma resposta 2xx. Redirecionamentos não são seguidos e contam como falha. Se a chamada falhar, são três tentativas no total: a segunda 10 segundos depois e a terceira 100 segundos depois. Esgotadas as três, o evento é descartado.

Por isso:

  • responda rápido e processe depois, numa fila sua;
  • trate o mesmo evento chegando duas vezes, porque uma resposta lenta pode gerar reenvio de algo que você já recebeu.