Markdown
Guia · validação

Da operação à entrega confirmada

O que guardar, como conferir cada etapa e quais testes executar antes de liberar a integração.

Use dados fictícios e somente um destinatário autorizado nos testes reais. Não use clientes como amostra de teste. Ensaios de timeout e eventos fora de ordem devem começar em ambiente local, com transporte simulado.

Escolher Cloud ou Marketing (link para esta seção)

UsoAPI de envio
Bilhete, reembolso e aviso transacionalcloud, com template UTILITY aprovado e compatível com a operação.
Código de verificaçãocloud, com template AUTHENTICATION e otp_code. A validade do código é responsabilidade do emissor.
Promoçãocloud ou marketing, com template MARKETING aprovado. marketing exige ativação concluída na Meta.
Resposta livre na janela de atendimentocloud. Confira a janela para o mesmo número remetente; ela não determina a cobrança.

No painel, Nova campanha mostra o seletor API de envio quando o template é de Marketing. Na integração, informe delivery_api em POST /public/v1/messages; omitir usa cloud. A escolha não aceita termos da Meta e não comprova que a conta está habilitada. Não há fallback automático.

Marketing Messages API oferece otimizações próprias de marketing; isso não garante mais entregas, menor custo ou maior velocidade. Nenhuma rota contorna consentimento, bloqueios ou pausas. Consulte pré-requisitos e sincronização e como comparar campanhas.

Uma operação por mensagem (link para esta seção)

Crie a tarefa no outbox antes do POST. Um mesmo pedido pode gerar bilhete, devolução e aviso: cada mensagem tem referência e chave próprias. Uma campanha precisa de uma operação por destinatário. A Patrocinio não conhece o seu pedido; esse vínculo fica no seu banco.

GuardarFinalidade
Empresa e conexãoIsolar operações, credenciais e eventos de cada integração.
ID da operação e do pedidoAssociar, por exemplo, outbox:8421 ao pedido interno. Não reutilize o client_ref em outra mensagem.
client_ref e Idempotency-KeyReferência para conciliação e chave para repetição segura, ambas persistidas antes do envio.
phone_number_id e destinatário solicitadoRegistrar o remetente e o telefone internacional informado na operação.
Payload e delivery_apiPreservar a identidade da operação. Proteja os dados necessários; não grave OTP, tokens ou credenciais em logs.
message_id e data.toGuardar o aceite e o destinatário canônico retornado. Não sobrescreva o telefone original.
delivery_api_confirmedGuardar a evidência Meta recebida no status/webhook. null significa ausência de evidência.
Status, erro e eventosManter o histórico e o estado consolidado sem perder falhas nem regredir entregas.
Idempotency-Key é opcional no contrato HTTP e recomendado em todo envio automatizado. Sem ele, repetir o POST pode enviar outra mensagem. client_ref também é opcional: o envio não impõe unicidade nem deduplica por esse campo. Garanta uma referência única por operação na empresa; duplicatas tornam a consulta ambígua (409 ambiguous_client_ref).

Uma resposta repetida com idempotent_replay: true recupera o aceite anterior. O status: sent desse replay não é o estado atual: consulte o status ou processe o webhook sem rebaixar uma mensagem já entregue.

Consolidar os status sem regressão (link para esta seção)

A mesma regra vale para bilhetes e campanhas. Não compare apenas o número de status_rank: failed é um ramo próprio. Uma entrega confirmada prevalece sobre falha ou aceite atrasados.

JavaScript · transição de status
function proximoStatus(atual, recebido) {
  const entrega = { delivered: 3, read: 4, played: 5 };
  if (Object.hasOwn(entrega, recebido)) {
    return (entrega[atual] || 0) > entrega[recebido] ? atual : recebido;
  }
  // Uma falha nunca apaga uma entrega/leitura já comprovada.
  if (recebido === "failed") return entrega[atual] ? atual : "failed";
  // O aceite atrasado também não desfaz uma falha confirmada.
  if (recebido === "sent") return entrega[atual] || atual === "failed" ? atual : "sent";
  return atual; // Estado desconhecido: preserve e encaminhe para análise.
}

Aplique a função dentro de uma transação, com bloqueio da operação ou atualização condicional. Grave cada evento para auditoria, mesmo quando não mudar o estado final. Contadores de campanha devem refletir a transição efetiva; repetir um evento não incrementa o funil. Recusa de promoções é uma dimensão separada: não apaga uma entrega anterior.

Eventos recebidos nesta ordemEstado final esperado
delivered → sent → faileddelivered
sent → failed → sentfailed
failed → delivered → read → deliveredread
read → failed → read (repetido)read, sem contar outra leitura

Quando o webhook chega primeiro (link para esta seção)

Valide a assinatura, descarte testes sem efeitos e grave eventos reais de forma durável antes do 2xx. Deduplique pelo identificador da conexão e delivery_id. Localize a operação por message_id ou pelo client_ref já salvo, conferindo a empresa e o remetente.

Se os identificadores apontarem para operações diferentes, preserve o evento para revisão. Sem correspondência, mantenha uma fila de conciliação com tentativas limitadas e alerta; não marque como processado nem associe a um pedido apenas pelo telefone. Envios feitos no painel podem não ter uma operação no seu sistema.

Um HTTP 200 com unknown_message no corpo do seu receptor confirma apenas que ele aceitou o webhook. A Patrocinio não interpreta esse texto para repetir o evento. O receptor precisa guardar o evento e conciliá-lo; veja o exemplo com fila durável.

Erros que não devem disparar outra mensagem (link para esta seção)

CódigoTratamento
delivery_api_template_mismatch · 422Corrigir a combinação de categoria e rota. Recusa desta tentativa; não repetir em laço nem trocar a rota automaticamente.
marketing_api_not_ready · 422Revisar ativação e permissões na Meta. Suspender novas tentativas até corrigir a configuração.
cloud_marketing_disabled · 422Marketing por Cloud indisponível para a conta. Rever a configuração sem fallback automático.
send_uncertainResultado sem confirmação, inclusive em destinatários de campanha. Preservar a operação e conciliar; não gerar novo envio.
idempotency_in_flight · 409Tentativa em andamento ou incerta. Consultar com a chave original; repetição limitada mantém chave e corpo.
ambiguous_client_ref · 409Referência reutilizada. Consultar pela Idempotency-Key original ou message_id; corrigir a unicidade do outbox.

Consulte GET /messages/status com a chave no header ou a referência na query, uma opção por chamada. unconfirmed e 404 não comprovam falha nem autorizam reenvio. Confira os demais erros, limites e política de retry.

Roteiro de validação (link para esta seção)

TesteCritério de aceite
Contrato e catálogoLer OpenAPI, números e templates da conta. Validar categoria, idioma, variáveis, botões e mídia real do envio.
Idempotência localSimular duas chamadas simultâneas, timeout e resposta repetida: uma só operação. Mudar rota com a mesma chave resulta em conflito.
Webhook antes do POST responderEncontrar a operação pelo client_ref. Sem vínculo, preservar para conciliação sem dar baixa no evento.
Eventos duplicados e fora de ordemExecutar as sequências acima, inclusive com workers concorrentes; conferir status e contadores de campanha.
Assinatura e isolamentoRejeitar assinatura inválida, respeitar a tolerância de horário e nunca vincular evento à operação de outra empresa.
Teste pelo painelValidar os cinco eventos com data.test === true: 2xx após assinatura, sem alterar contatos, pedidos, consentimentos ou métricas.
Envio real autorizadoRegistrar operação, aceite, destinatário canônico e delivered/read por webhook. Falha deve preservar o código e a causa.
Cloud versus MarketingRegistrar rota solicitada e confirmada. Uma entrega isolada valida o caminho; não prova ganho de desempenho ou economia.
Falha do receptorSimular indisponibilidade, recuperar a fila e conferir deduplicação. Reentregar webhook não reenvia mensagem no WhatsApp.
Cota e consentimentoLeituras e escritas compartilham 600/min por chave. Respeitar Retry-After; marketing_allowed não comprova aceite, e inbound não prova consentimento para campanha.

A mídia deve estar acessível à Meta sem login. Não reutilize a URL temporária de amostra do catálogo como arquivo de produção: use o documento ou imagem daquela operação, com validade suficiente para download. Um arquivo que abre no painel ainda pode ser recusado quando a Meta o buscar.

Registre separadamente testes locais, chamadas pelo serviço interno, HTTP autenticado da API pública e confirmação no telefone. Não trate teste sintético de webhook como envio real, nem 200 do receptor como prova de vínculo ao pedido.