Erros da API do WhatsApp: o que cada um significa e como tratar
A mensagem não saiu e o log só diz 'erro ao enviar'. Os erros reais — janela fechada, número inválido, template recusado — e como tratar cada um.
"Erro ao enviar mensagem." É o que a maioria dos logs registra, e é inútil: não diz se é para repetir, avisar alguém ou desistir.
Este artigo separa os erros que você de fato vai encontrar e o tratamento certo para cada um.
Primeiro: 200 não é entrega
const r = await enviar(to, texto); // 200 OK
// isso NÃO quer dizer que a mensagem chegou200 significa que a plataforma aceitou a mensagem. A entrega é confirmada depois, pelo webhook de status — em value.statuses, como delivered ou failed.
Quem só olha o retorno da chamada nunca fica sabendo das falhas de entrega. É por isso que medir com o webhook de status não é opcional.
A divisória que organiza tudo
| Temporário | Definitivo | |
|---|---|---|
| Exemplos | Limite atingido, 5xx, timeout, instância caída | Número inválido, template não aprovado, janela fechada, bloqueado |
| Ação | Repetir com backoff | Não repetir |
| Registrar como | Pendente | Falha, com o motivo |
Repetir erro definitivo é o desperdício mais comum em fila de disparo: gasta cota, atrasa quem está atrás e nunca dá certo.
Os erros, um a um
Janela de 24 horas fechada
O mais comum de todos em quem está começando com notificação.
Você tentou mandar texto livre para alguém que não escreve há mais de 24 horas. Na API oficial, isso não sai.
if (e.code === 'fora_da_janela') {
// Não repita: em 5 minutos vai dar o mesmo erro.
// Reenvie como template aprovado.
return enviarTemplate(to, 'aviso_generico', params);
}O tratamento não é retry — é usar template. Se o seu fluxo manda notificação, ele sempre vai encontrar a janela fechada, porque a mensagem parte de você.
Número inválido ou sem WhatsApp
Definitivo. Marque e siga:
if (e.code === 'sem_whatsapp' || e.code === 'numero_invalido') {
await db.contatos.marcar(to, 'invalido');
return; // nunca mais tente este número
}Prevenir é melhor: verifique a base antes da campanha. Na API oficial, tentativa falha repetida prejudica a reputação do número. O procedimento está em higienização de lista.
Template não aprovado ou pausado
Definitivo, e exige gente:
if (e.code === 'template_nao_aprovado') {
await alertarTime(`Template ${nome} indisponível — campanha pausada`);
await pausarCampanha(campanhaId);
return;
}Pause a campanha inteira, não só a mensagem. Se o template caiu, as próximas 5.000 vão falhar igual — e cada tentativa piora o quadro.
Template aprovado pode ser pausado depois, se receber muito bloqueio. Aprovação não é permanente.
Limite atingido
Temporário, e o tratamento errado piora:
if (e.status === 429) {
const espera = Number(e.headers?.['retry-after'] ?? 60) * 1000;
throw new ErroTemporario(espera); // a fila cuida do backoff
}Respeite o Retry-After quando ele vier. Sem ele, backoff exponencial com jitter — repetir tudo junto no mesmo instante recria o mesmo limite. O desenho completo está em fila, rate limit e retry.
Instância desconectada
Temporário, mas não adianta repetir em 2 segundos: alguém precisa reconectar.
if (e.code === 'instancia_desconectada') {
await alertarTime(`Instância de ${cliente.nome} caiu`);
await notificarCliente(cliente, 'canal_desconectado');
throw new ErroTemporario(15 * 60 * 1000); // tenta de novo em 15 min
}Avisar o cliente antes de ele perceber muda a conversa: de "seu sistema está quebrado" para "vimos que caiu e já estamos resolvendo".
Isso pesa mais na API não oficial, em que a sessão pode cair sozinha. A Conexão Mobile elimina a causa mais comum, que é o celular.
Mídia recusada
Definitivo, quase sempre por URL:
if (e.code === 'midia_invalida') {
// Causas: URL não pública, sem HTTPS, arquivo grande demais,
// formato não suportado, ou o servidor devolvendo HTML no lugar do arquivo.
await db.envios.marcar(id, 'midia_invalida');
return;
}O caso mais traiçoeiro é a URL que exige autenticação: no seu navegador abre (você tem sessão), e para a plataforma volta a página de login. Teste sempre em janela anônima.
Contato bloqueou
Definitivo, e é informação valiosa:
if (e.code === 'contato_bloqueou') {
await db.contatos.marcar(to, 'bloqueou');
await registrarNaMetrica(campanhaId, 'bloqueio');
return;
}Não trate como falha técnica. Bloqueio é sinal de conteúdo, e é o indicador que avisa antes de o número queimar.
O handler que amarra tudo
const DEFINITIVOS = new Set([
'sem_whatsapp', 'numero_invalido', 'template_nao_aprovado',
'contato_bloqueou', 'midia_invalida', 'fora_da_janela',
]);
async function enviarComTratamento(job) {
const { to, payload, campanhaId } = job.data;
try {
const r = await api.enviar(to, payload);
await db.envios.sucesso(campanhaId, to, r.messageId);
} catch (e) {
const definitivo = DEFINITIVOS.has(e.code) ||
(e.status >= 400 && e.status < 500 && e.status !== 429);
// Log com o que permite agir: código, destinatário, tentativa.
// "erro ao enviar" não permite nada.
console.error({
evento: 'falha_envio',
campanha: campanhaId,
to,
code: e.code,
status: e.status,
tentativa: job.attemptsMade + 1,
definitivo,
});
if (definitivo) {
await db.envios.falha(campanhaId, to, e.code);
return; // não repete
}
throw e; // repete com backoff
}
}O que registrar
Log que serve tem código, destinatário e número da tentativa. Com isso você responde as três perguntas que aparecem quando algo dá errado:
- Qual erro está crescendo hoje?
- Este número falha sempre ou foi uma vez?
- Estamos repetindo algo que nunca vai funcionar?
Um alerta simples fecha o ciclo: se a taxa de falha de uma campanha passar de 10%, pare e avise. Campanha que falha em massa com o template pausado consome cota e piora a reputação a cada tentativa.
Conclusão
Tratamento de erro em API de mensagem é uma decisão só, repetida: isto muda se eu tentar de novo?
Se muda, é fila e backoff. Se não muda, é registro com motivo e seguir adiante. Errar essa classificação é o que faz uma fila travar por horas repetindo "número não existe" — ou desistir de mensagens que teriam saído na segunda tentativa.
Pronto para automatizar seu WhatsApp?
Crie sua conta gratuita e comece a enviar mensagens pela API em minutos.
Começar grátisPerguntas frequentes
Por que minha mensagem não é entregue mesmo com status 200?+
Porque 200 significa que a plataforma aceitou a mensagem para envio, não que ela chegou. A entrega é confirmada depois, pelo webhook de status. Se você só olha o retorno da chamada, nunca vai saber que a mensagem falhou na entrega.
O que significa o erro de janela de 24 horas?+
Que você tentou enviar mensagem livre para alguém que não escreve há mais de 24 horas. Fora dessa janela, a API oficial só aceita template previamente aprovado. É o erro mais comum em quem está integrando notificações pela primeira vez.
O que fazer quando a API retorna limite atingido?+
Esperar e repetir com intervalo crescente e alguma variação aleatória. Repetir imediatamente piora a situação, porque a nova tentativa cai no mesmo limite. O tratamento correto é backoff exponencial com jitter, e uma fila que controle o ritmo para o limite não ser atingido de novo.
Como saber se a instância está desconectada antes de tentar enviar?+
Consultando o estado da instância. Vale ter uma verificação periódica que alerta antes de o cliente perceber, e uma verificação no worker que evita queimar tentativas enviando para uma instância que já se sabe fora do ar.
Devo repetir todo erro automaticamente?+
Não. Repetir só faz sentido em erro temporário: limite, indisponibilidade, timeout e falha de rede. Erro definitivo — número inexistente, template não aprovado, contato bloqueado — não muda com nova tentativa; repetir gasta cota e atrasa a fila.
Continue lendo
Mídia no webhook do WhatsApp: como receber, baixar e os limites de tamanho por canal
O webhook traz a referência da mídia, não o arquivo. Como baixar imagem, áudio, vídeo e documento pela API, em base64 ou binário, e os limites de tamanho de WhatsApp, Instagram e Messenger.
Bloqueios em massa do WhatsApp: o que aconteceu e quem foi atingido
A onda de bloqueios de contas do WhatsApp em agosto de 2026 atingiu negócios inteiros. O que os casos tinham em comum, por que a Meta agiu em lote e quem passou ileso.
Como criar um CRM do zero com IA
A IA entrega modelo de dados, funil e painel em dias. Ela não entrega canal, entrega de mensagem nem multi-inquilino. O que fazer com cada uma das três partes.