# 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

| Uso | API de envio |
| --- | --- |
| Bilhete, reembolso e aviso transacional | cloud, com template UTILITY aprovado e compatível com a operação. |
| Código de verificação | cloud, com template AUTHENTICATION e otp\_code. A validade do código é responsabilidade do emissor. |
| Promoção | cloud ou marketing, com template MARKETING aprovado. marketing exige ativação concluída na Meta. |
| Resposta livre na janela de atendimento | cloud. 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](https://patrociniotech.com/documentacao-api/mensagens.md) e [como comparar campanhas](https://patrociniotech.com/documentacao-api/campanhas.md).

## Uma operação por mensagem

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.

| Guardar | Finalidade |
| --- | --- |
| Empresa e conexão | Isolar operações, credenciais e eventos de cada integração. |
| ID da operação e do pedido | Associar, por exemplo, outbox:8421 ao pedido interno. Não reutilize o client\_ref em outra mensagem. |
| client\_ref e Idempotency-Key | Referência para conciliação e chave para repetição segura, ambas persistidas antes do envio. |
| phone\_number\_id e destinatário solicitado | Registrar o remetente e o telefone internacional informado na operação. |
| Payload e delivery\_api | Preservar a identidade da operação. Proteja os dados necessários; não grave OTP, tokens ou credenciais em logs. |
| message\_id e data.to | Guardar o aceite e o destinatário canônico retornado. Não sobrescreva o telefone original. |
| delivery\_api\_confirmed | Guardar a evidência Meta recebida no status/webhook. null significa ausência de evidência. |
| Status, erro e eventos | Manter 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

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

```javascript
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 ordem | Estado final esperado |
| --- | --- |
| delivered → sent → failed | delivered |
| sent → failed → sent | failed |
| failed → delivered → read → delivered | read |
| read → failed → read (repetido) | read, sem contar outra leitura |

## Quando o webhook chega primeiro

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](https://patrociniotech.com/documentacao-api/exemplo.md).

## Erros que não devem disparar outra mensagem

| Código | Tratamento |
| --- | --- |
| delivery\_api\_template\_mismatch · 422 | Corrigir 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 · 422 | Revisar ativação e permissões na Meta. Suspender novas tentativas até corrigir a configuração. |
| cloud\_marketing\_disabled · 422 | Marketing por Cloud indisponível para a conta. Rever a configuração sem fallback automático. |
| send\_uncertain | Resultado sem confirmação, inclusive em destinatários de campanha. Preservar a operação e conciliar; não gerar novo envio. |
| idempotency\_in\_flight · 409 | Tentativa em andamento ou incerta. Consultar com a chave original; repetição limitada mantém chave e corpo. |
| ambiguous\_client\_ref · 409 | Referê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](https://patrociniotech.com/documentacao-api/erros.md).

## Roteiro de validação

| Teste | Critério de aceite |
| --- | --- |
| Contrato e catálogo | Ler OpenAPI, números e templates da conta. Validar categoria, idioma, variáveis, botões e mídia real do envio. |
| Idempotência local | Simular 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 responder | Encontrar a operação pelo client\_ref. Sem vínculo, preservar para conciliação sem dar baixa no evento. |
| Eventos duplicados e fora de ordem | Executar as sequências acima, inclusive com workers concorrentes; conferir status e contadores de campanha. |
| Assinatura e isolamento | Rejeitar assinatura inválida, respeitar a tolerância de horário e nunca vincular evento à operação de outra empresa. |
| Teste pelo painel | Validar os cinco eventos com data.test === true: 2xx após assinatura, sem alterar contatos, pedidos, consentimentos ou métricas. |
| Envio real autorizado | Registrar operação, aceite, destinatário canônico e delivered/read por webhook. Falha deve preservar o código e a causa. |
| Cloud versus Marketing | Registrar rota solicitada e confirmada. Uma entrega isolada valida o caminho; não prova ganho de desempenho ou economia. |
| Falha do receptor | Simular indisponibilidade, recuperar a fila e conferir deduplicação. Reentregar webhook não reenvia mensagem no WhatsApp. |
| Cota e consentimento | Leituras 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.

---

Fonte: https://patrociniotech.com/documentacao-api/validacao
Índice para IA: https://patrociniotech.com/documentacao-api/llms.txt
