Cobrança, Pix e boleto

WhatsApp com o webhook do Asaas: avise quando o Pix for pago ou a cobrança vencer

O Asaas envia um POST para a sua URL a cada mudança de cobrança, com o nome do evento em event e o objeto payment. Esse payload traz o id do cliente (payment.customer), mas não traz o celular dele. Por isso a ligação com o WhatsApp passa por um passo seu: receber o evento, buscar o cliente no Asaas e chamar a API da ZapZap. Esta página mostra esse caminho completo, com código, e diz quando ele não vale a pena.

Atualizado em

Por que conectar

Quem cobra por Pix, boleto ou cartão no Asaas perde tempo com duas perguntas repetidas: o cliente diz que pagou e você não vê, ou esquece que a cobrança venceu. Com o webhook ligado, o pagamento confirmado gera uma mensagem de recibo em segundos e a cobrança vencida gera um lembrete no mesmo dia, sem ninguém abrir o painel. O WhatsApp serve para avisar quem já é cliente: mande só para quem tem relação com você e deixe claro como parar de receber. A ZapZap conecta números por um canal não oficial e gerenciado, então o ritmo e o consentimento contam. São R$15 por número ativo/mês, pré-pago, e você começa com crédito de boas-vindas ao criar a conta, sujeito à campanha vigente.

Passo a passo

  1. 1

    Crie o webhook no Asaas com token de autenticação

    No Asaas, crie um webhook pela aplicação web ou pela API (até 10 por conta) apontando para o seu endpoint HTTPS, e marque só os eventos que usar, por exemplo PAYMENT_RECEIVED e PAYMENT_OVERDUE. Defina o authToken: o Asaas o envia em todas as notificações no cabeçalho asaas-access-token. Ele deve ter de 32 a 255 caracteres, sem espaços, e não pode ser uma API Key do Asaas. Teste primeiro no Sandbox: as configurações de Sandbox e Produção são independentes.

  2. 2

    Valide o token e grave o evento antes de responder

    No endpoint, compare o cabeçalho asaas-access-token com o seu token e recuse (401) se não bater. Depois grave o id do evento numa tabela com restrição de unicidade e só então responda HTTP 200. O Asaas entrega cada evento pelo menos uma vez, então o mesmo id pode chegar repetido, e o id é a sua chave de idempotência. Resposta lenta provoca timeout, por isso o envio do WhatsApp vai para depois do 200.

  3. 3

    Busque o celular do cliente

    O payload traz payment.customer (algo como cus_000005913252), não o telefone. Faça GET https://api.asaas.com/v3/customers/{id} com o cabeçalho access_token e leia mobilePhone (celular) ou phone (fixo ou geral). Se os dois vierem vazios, não há para quem enviar: registre e siga em frente. Normalize para dígitos e acrescente o 55 do Brasil se faltar.

  4. 4

    Envie a mensagem pela API da ZapZap

    Chame POST https://api.zapzapapi.com/api/v1/{instanceId}/send/text com x-api-key, x-api-secret e o JSON com number e text. Monte o texto com o nome, o valor (payment.value) e o link da cobrança, se você guardar um. Trate 429 e 5xx com nova tentativa espaçada, e 400, 401 e 403 como erro de configuração, sem repetir.

  5. 5

    Reative sozinho a fila se ela pausar

    Depois de 15 falhas consecutivas de entrega o Asaas interrompe a fila daquele webhook, guarda os eventos pendentes por até 14 dias e avisa por e-mail. Corrija o endpoint, reative a fila no painel do Asaas e confira em Integrações > Logs de Webhooks o código HTTP e as tentativas. Vale um alerta seu para erro 5xx no endpoint, porque ninguém olha o e-mail do Asaas todo dia.

Exemplo

// Express: recebe o evento do Asaas e avisa o cliente pelo WhatsApp
import express from 'express';
const app = express();

app.post('/asaas', express.json(), async (req, res) => {
  if (req.get('asaas-access-token') !== process.env.ASAAS_WEBHOOK_TOKEN) return res.sendStatus(401);
  const { id, event, payment } = req.body;

  // Idempotência: INSERT com UNIQUE no id do evento. Se já existe, só confirma.
  const novo = await salvarEventoUnico(id, req.body); // sua função
  res.sendStatus(200); // responda 200 logo depois de gravar
  if (!novo || event !== 'PAYMENT_RECEIVED') return;

  const cli = await fetch('https://api.asaas.com/v3/customers/' + payment.customer, {
    headers: { access_token: process.env.ASAAS_API_KEY },
  }).then((r) => r.json());
  const fone = String(cli.mobilePhone || cli.phone || '').replace(/\D/g, '');
  if (!fone) return;

  await fetch('https://api.zapzapapi.com/api/v1/' + process.env.ZAPZAP_INSTANCE + '/send/text', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.ZAPZAP_API_KEY,
      'x-api-secret': process.env.ZAPZAP_API_SECRET,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      number: fone.startsWith('55') ? fone : '55' + fone,
      text: 'Oi, ' + cli.name + '! Recebemos o seu pagamento de R$ ' + payment.value + '. Obrigado!',
    }),
  });
});

Ilustrativo. Os campos e endpoints exatos estão na documentação.

Quais eventos do Asaas valem uma mensagem

A lista de eventos de cobrança do Asaas é longa (estornos, chargeback, Split, negativação). Para o dia a dia de cobrança, quatro bastam, e o que importa é escolher um por objetivo para não mandar duas mensagens sobre o mesmo fato.

EventoQuando ocorre (segundo o Asaas)Uso com WhatsApp
PAYMENT_CREATEDGeração de nova cobrança.Aviso de cobrança nova, se o cliente espera por ele.
PAYMENT_CONFIRMEDPagamento efetuado, mas com saldo ainda não disponibilizado.Cartão: primeiro sinal de pagamento. Use este ou o RECEIVED, não os dois.
PAYMENT_RECEIVEDCobrança recebida, com valor disponível na conta Asaas.Recibo e liberação de acesso.
PAYMENT_OVERDUECobrança vencida.Lembrete de vencimento, com tom de ajuda.

Segurança, idempotência e o que o Asaas pede de você

  • Autenticação: o Asaas não assina o corpo com HMAC. O que existe é o authToken, enviado no cabeçalho asaas-access-token. Valide sempre, e se a sua infraestrutura filtra por origem, use a lista de IPs oficiais do Asaas.
  • Idempotência: o id do evento é único e se repete nas reentregas. Grave-o com restrição de unicidade antes de processar, e use também payment.id para não avisar duas vezes o mesmo pagamento.
  • Resposta: devolva HTTP 200. A página de fila pausada diz que apenas 200 conta como sucesso, enquanto a de penalização cita qualquer 2xx; use 200 e fique no lado seguro.
  • Retentativas: a primeira falha tenta de novo em 30 segundos, depois 1 minuto, 3 min 30 s e assim por diante, com intervalos que chegam a 3 horas. Na 15ª falha consecutiva a fila pausa.
  • Reaproveitamento: um webhook do Asaas, um endpoint seu. Dê a ele uma fila interna e processe o envio do WhatsApp em segundo plano.

Quando NÃO usar este caminho

Se o seu objetivo é recuperar carrinho abandonado de infoproduto, o Asaas não é o lugar: ele cobra, não monitora checkout. Nesse caso, veja a Kiwify, a Hotmart ou a Eduzz, que têm evento de carrinho e já entram no assistente de Recuperação de Vendas da ZapZap sem código. Se você não tem quem mantenha um endpoint, use o n8n com um nó Webhook e um nó HTTP Request, que faz o mesmo caminho sem servidor próprio. E não use WhatsApp para cobrar quem nunca falou com você: sem relação prévia e sem consentimento, o risco de denúncia e de bloqueio do número é alto, e a LGPD exige base legal para o contato.

Fontes e data da conferência

Eventos, estrutura do payload, idempotência, cabeçalho asaas-access-token, regras do token, retentativas e fila pausada foram conferidos em 29/10/2026 na documentação oficial do Asaas (docs.asaas.com), nas páginas Eventos para cobranças, Receba eventos do Asaas no seu endpoint de Webhook, Como implementar idempotência em Webhooks, Fila pausada e Penalização de filas. O campo mobilePhone vem da referência Recuperar um único cliente. Documentação muda: confira as páginas antes de ir para produção.

Perguntas frequentes

O Asaas envia o telefone do cliente no webhook?

Não. O objeto payment traz o id do cliente em payment.customer. O celular você busca com GET /v3/customers/{id}, no campo mobilePhone ou phone. Por isso a ligação com a ZapZap passa por um endpoint ou por um fluxo no n8n, e não pelo gatilho de webhook direto da ZapZap.

Como sei que o webhook veio mesmo do Asaas?

Configure o authToken no webhook e compare com o cabeçalho asaas-access-token em toda requisição. Não é uma assinatura HMAC do corpo, é um token fixo, então guarde-o como segredo e nunca use uma API Key do Asaas no lugar dele. Se você restringe por origem, use os IPs oficiais publicados pelo Asaas.

Recebi o mesmo evento duas vezes. É erro?

Não. A entrega é pelo menos uma vez, e o mesmo id pode chegar repetido. Grave o id do evento com restrição de unicidade e ignore o que já foi processado. Sem isso, o cliente recebe o mesmo recibo duas vezes.

O que acontece se o meu servidor ficar fora do ar?

O Asaas tenta de novo com intervalos crescentes. Depois de 15 falhas consecutivas ele pausa a fila daquele webhook e guarda os eventos por até 14 dias. Corrija o endpoint e reative a fila no painel; passado esse prazo, os eventos mais antigos são apagados.

Posso usar o Sandbox para testar?

Pode e deve. As configurações de Sandbox e Produção são independentes, então repita o cadastro do webhook em produção depois de validar o fluxo. No lado da ZapZap, teste com o seu próprio número antes de mandar para clientes.

Qual evento uso para avisar que o Pix foi pago?

PAYMENT_RECEIVED indica cobrança recebida com valor disponível na conta. PAYMENT_CONFIRMED indica pagamento efetuado com saldo ainda não disponibilizado. Escolha um dos dois para a mensagem e use payment.id para não avisar duas vezes.

Posso mandar cobrança por WhatsApp para qualquer cliente?

Só para quem tem relação com você e espera esse contato. Use um tom de lembrete, sem constrangimento, e ofereça um jeito de parar de receber. A ZapZap é um canal não oficial e não elimina o risco de bloqueio; consentimento, ritmo humano e lista limpa continuam sendo seus.

Comece agora

Crie sua conta, conecte um número em minutos e teste a API com aquecimento e anti-bloqueio. R$15 por número ativo/mês, pré-pago, sem fidelidade.