Markdown
Referência · diagnóstico

Erros e limites

Use o status HTTP e error.code para decidir entre corrigir os dados, aguardar ou verificar uma operação sem confirmação.

JSON · exemplo de recusa
{
  "success": false,
  "error": {
    "code": "outside_24h_window",
    "message": "Faz mais de 24h que essa pessoa não escreve. Envie um template aprovado."
  }
}

error.code identifica a condição para sua aplicação. error.message explica o problema para uma pessoa e pode mudar sem alterar o contrato.

Em 422 invalid_request, error.details.fields indica até 20 campos inválidos, com caminho, código e orientação. Os valores enviados não são devolvidos. O campo details é opcional: trate também erros que só tenham código e mensagem.

JSON · campo inválido
{
  "success": false,
  "error": {
    "code": "invalid_request",
    "message": "Dados inválidos. Revise os campos.",
    "details": {
      "fields": [
        { "field": "body.header_media.link", "code": "url_parsing", "message": "Informe uma URL válida." }
      ]
    }
  }
}

Guarde o header X-Request-Id, o status HTTP e o código do erro junto à sua operação. Use essa referência para investigar uma chamada com o suporte; não registre o header Authorization nem códigos de autenticação.

O que fazer com cada resposta (link para esta seção)

HTTPInterpretação e ação
200Leia data. No envio, sent significa aceite; confirme entrega pelo webhook.
400 / 422Corrija os campos ou a regra indicada em error.code. 422 também cobre validações locais, não apenas recusas da Meta.
401Confira o header Authorization e se a chave foi revogada.
404Confira o identificador e a conta à qual o recurso pertence.
409Confira a operação original. Não troque a chave para contornar idempotência.
429Reduza o ritmo e respeite Retry-After quando informado.
5xx / falha de conexãoO resultado pode estar incerto. Preserve corpo e chave ao tentar novamente.
Uma resposta sem confirmação não prova que a mensagem deixou de ser enviada. A sua política de retry deve manter a mesma Idempotency-Key, limitar tentativas e encaminhar casos persistentes para conferência.

Encontrar o código de erro (link para esta seção)

Dados da requisição

CódigoCorreção
invalid_requestConfira error.details.fields, tipos e limites no OpenAPI. Campos desconhecidos no envio são recusados; não são ignorados.
invalid_recipientUse telefone internacional com DDI e DDD. Para um cadastro local, normalize antes com POST /validate e country; o envio não acrescenta 55.
empty_message / ambiguous_messageInforme text ou template. Não deixe ambos ausentes nem envie os dois juntos.
invalid_idempotency_keyInforme uma chave não vazia, de até 64 caracteres.
variable_too_longReduza a variável ao limite de 1.024 caracteres, sem perder dados essenciais.
variable_bad_format / template_param_formatRemova quebras de linha, tabulações e sequências de mais de quatro espaços das variáveis.
invalid_pix_order / pix_needs_templateConfira o template de cobrança, os campos PIX e a soma dos itens em centavos.

Template e conteúdo

CódigoCorreção
outside_24h_windowUse template aprovado quando a janela de texto livre estiver fechada.
template_not_foundConfira nome, idioma e número conectado.
invalid_template / template_pausedConfira aprovação, qualidade e disponibilidade do modelo na Meta.
template_format_unsupportedConsulte api_supported e api_unsupported_reason e escolha um modelo compatível.
template_params_mismatchConfira quantidade e nomes das variáveis, cabeçalho e posição dos botões.
template_required_header_mediaEnvie o arquivo exigido em header_media ou use o modelo sem anexo.
template_header_mismatchUse o tipo de mídia ou texto de cabeçalho exigido pelo modelo.
invalid_otpConfira código, categoria AUTHENTICATION e botão no índice 0. Não use campos de cupom.
invalid_template_statusNa consulta de templates, use APPROVED, ALL ou outro status documentado. Não envie um filtro vazio.

Consulta e recuperação do webhook

CódigoAção
invalid_statusUse pending, delivering, delivered ou failed ao consultar a fila do webhook.
invalid_eventNo filtro de entregas, use um dos eventos documentados: message.status, message.received, contact.marketing_opt_out, template.status ou template.quality.
invalid_status_lookupNa consulta GET /messages/status, informe client_ref ou o cabeçalho Idempotency-Key, nunca os dois nem um valor vazio.
ambiguous_client_refA referência foi reutilizada em mais de uma tentativa. Consulte pela chave de idempotência original ou pelo message_id; a API não escolhe o registro mais recente.
not_foundA entrega não existe nesta conta. Confira o identificador retornado pela listagem.
message_not_foundO envio não foi encontrado nesta conta. Confira message_id, eventos e retenção. Um 404 não comprova que a mensagem não foi enviada e não deve provocar reenvio automático.
not_retryableA entrega não existe nesta conta ou não está em failed ou delivered. Confira o identificador e o estado antes de reenviar.

Acesso, destinatário e conta

CódigoAção
missing_api_key / invalid_api_keyConfira a chave no servidor e o header Authorization. Revogue a credencial se houver exposição.
no_connected_numberConfira o número selecionado e a conexão da conta no painel.
recipient_unreachableA mensagem não pôde ser entregue. O código Meta 131026 não confirma ausência de WhatsApp. Confira o telefone com o cliente antes de reenviar.
marketing_not_allowedO contato recusou promoções ou está bloqueado para marketing. Não repita o envio promocional. Avisos transacionais usam templates de utilidade adequados ao pedido.
marketing_experimentA entrega de marketing foi limitada para esse destinatário. Não tente contornar a restrição com repetições.
marketing_recipient_limitedMeta 131049: marketing limitado para esse destinatário. Não comprova bloqueio do número da empresa. Evite repetir imediatamente.
delivery_limitedMeta 131048: entrega limitada por qualidade ou sinais de spam. Confira a situação do número e a qualidade dos envios na Meta.
account_restrictedConfira e resolva a restrição da conta na Meta antes de repetir.
payment_issueConfira a elegibilidade de pagamento e a configuração de cobrança na Meta. O código 131042 não comprova saldo insuficiente.

Uma mensagem aceita para processamento ainda pode falhar por pagamento. Confira o status pelo webhook antes de reenviar; se houver cobrança pré-paga, verifique também o saldo no painel da Meta. A modalidade de cobrança não muda o endpoint de envio.

O erro 131026 pode ocorrer por número sem cadastro, aplicativo desatualizado ou termos ainda não aceitos pelo destinatário. A Meta não distingue essas causas nesse código. Peça ao cliente, por outro canal, que confirme o telefone e tente iniciar uma conversa com o número da empresa. Consulte os códigos de erro da Meta.

Operação em andamento ou indisponibilidade

CódigoNova tentativa
idempotency_in_flightAguarde e use a mesma chave e corpo. Se continuar sem confirmação, confira os eventos.
idempotency_conflictNão repita automaticamente: a chave pertence a outro conteúdo.
idempotency_legacy_unverifiedConfira o registro antigo e os eventos; a API não pode comparar o conteúdo.
api_rate_limitedRespeite o teto por chave e Retry-After quando informado.
rate_limitedReduza o ritmo; este limite foi informado pela Meta.
templates_unavailable / meta_unavailable / db_unavailableAguarde e use a mesma chave e conteúdo, com limite de tentativas.
network_error / send_failedPreserve a operação, confira os status e investigue antes de iniciar outro envio.

Limites da integração (link para esta seção)

ItemLimite
Requisições da API600 por minuto, por chave, somando todos os endpoints autenticados e todos os workers que usam essa chave.
Idempotency-KeyAté 64 caracteres. Retenção padrão de dois dias; não substitui seu histórico permanente de operações.
Texto livreAté 4.096 caracteres.
Variáveis de templateAté 20 valores de 1.024 caracteres. Valores maiores são recusados, não cortados.
Código OTP / cupomAté 15 caracteres. São campos e tipos de botão diferentes.
Consulta de entregasAté 200 itens por página, com paginação por cursor.

O teto é de requisições, não de mensagens: enviar, validar telefone, consultar janela, consultar templates e acompanhar a fila consomem a mesma cota. Enviar a cada 100 ms já ocupa 600 chamadas por minuto, antes dessas consultas e das novas tentativas.

Use um limitador compartilhado entre os workers, reserve margem para consultas e reaproveite o catálogo e a janela recebida no webhook. Ao receber 429 api_rate_limited, pause a fila dessa chave pelo Retry-After; quando informado, error.details.retry_after_seconds traz a mesma pausa em segundos.

Acompanhar a cota antes do 429

Respostas de chamadas autenticadas que passaram pelo contador incluem os cabeçalhos abaixo, tanto em sucesso quanto em recusas posteriores. Falhas anteriores à autenticação, respostas do proxy ou uma conexão interrompida podem não ter esses campos.

CabeçalhoUso
X-RateLimit-LimitTeto da janela de um minuto: 600 requisições por chave.
X-RateLimit-RemainingSaldo imediatamente após contar esta chamada, nunca negativo. Chamadas concorrentes podem consumir o saldo antes da próxima requisição.
X-RateLimit-ResetInstante de início da próxima janela, em segundos Unix UTC. Não é uma duração.
X-RateLimit-Scopeapi_key: contador compartilhado. api_key_worker: contingência local quando o contador compartilhado está indisponível; mantenha seu próprio limitador global de 600/min.
Retry-AfterEm 429 por cota, segundos a aguardar. A Meta também pode limitar uma chamada independentemente do saldo local.
HTTP · exemplo de cota
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 541
X-RateLimit-Reset: 1793966460
X-RateLimit-Scope: api_key

O saldo é uma fotografia, não uma reserva para disparar esse volume imediatamente. Somar leituras e envios na mesma fila e manter margem evita que uma consulta em lote concorra com a entrega de mensagens transacionais.

O limite da Meta considera destinatários únicos em uma janela móvel de 24 horas e pode ser compartilhado pelo portfólio. Ele é separado dos 600 pedidos por minuto desta API. Consulte o limite atual no painel e no WhatsApp Manager; a qualidade do número não informa, sozinha, essa capacidade.

Exemplo de novas tentativas (link para esta seção)

Este exemplo trata uma operação: repete condições temporárias conhecidas, falhas de conexão e 5xx, mantendo corpo e chave, respeitando Retry-After e encerrando após quatro tentativas. Ele não substitui o limitador compartilhado da fila. Recusas desconhecidas não entram em retry automático.

Node.js · retry com a mesma operação
const TEMPORARIOS = new Set([
  "api_rate_limited", "rate_limited", "templates_unavailable",
  "meta_unavailable", "db_unavailable", "idempotency_in_flight",
]);
const esperar = (ms) => new Promise((ok) => setTimeout(ok, ms));

async function enviarComRetry(operacao) {
  const token = process.env.PT_API_KEY;
  const chave = operacao.chave;
  if (!token || !chave) throw new Error("Configure a chave de API e a chave da operação.");
50 linhas
estado retornado pelo exemploTratamento no seu sistema
aceitaGuarde o message_id. Aguarde o webhook para confirmar entrega.
recusadaMostre o motivo e corrija os dados ou a configuração antes de tentar novamente.
verificarMantenha a operação pendente de conferência. Consulte eventos; não crie outra chave automaticamente.

Execute em um worker e persista a operação antes de enviar. Para pausas longas, reagende na sua fila. Uma resposta de infraestrutura pode não ser JSON; o exemplo trata essa condição sem assumir sucesso.

Para a conciliação completa, veja envio e processamento do webhook.