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
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
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
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
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
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.
| Evento | Quando ocorre (segundo o Asaas) | Uso com WhatsApp |
|---|---|---|
| PAYMENT_CREATED | Geração de nova cobrança. | Aviso de cobrança nova, se o cliente espera por ele. |
| PAYMENT_CONFIRMED | Pagamento efetuado, mas com saldo ainda não disponibilizado. | Cartão: primeiro sinal de pagamento. Use este ou o RECEIVED, não os dois. |
| PAYMENT_RECEIVED | Cobrança recebida, com valor disponível na conta Asaas. | Recibo e liberação de acesso. |
| PAYMENT_OVERDUE | Cobranç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.
