Entenda o modelo, as limitações, e as armadilhas reais que custem tempo na integração.
Coexistência significa que o cliente continua usando o app WhatsApp Business normalmente no celular e ao mesmo tempo você controla a API.
Alternativas:
Pela política da Meta, texto livre só passa dentro de 24 horas desde a última mensagem do cliente final.
| Cenário | Resultado |
|---|---|
| Cliente mandou "Olá" às 10h. Você responde às 11h com texto livre. | ✓ Passa |
| Cliente mandou "Olá" às 10h. Você responde 25 horas depois com texto livre. | ✗ Falha (erro 131042) |
| Você envia template FORA da janela (dia seguinte). | ✓ Passa (templates não têm limite) |
| Agendamento para amanhã: template ou texto fora da janela? | Sempre fora — use template |
Template é mensagem pré-aprovada pela Meta. Qualquer uso fora da janela de 24h requer template.
| Estado | Pode enviar? | Nota |
|---|---|---|
APPROVED | ✓ Sim | Pronto para envio |
PENDING_REVIEW | ✗ Não | Aguardando aprovação da Meta (minutos até horas) |
REJECTED | ✗ Não | Meta recusou — motivo em rejection_reason |
PAUSED | ✗ Não | Meta pausou por qualidade — ainda há erro 131042 ao tentar |
DISABLED | ✗ Não | Você desabilitou ou Meta desabilitou |
LIMIT_EXCEEDED | ✗ Não | Conta atingiu limite de templates |
whatsapp.template.status com o novo estado.
confirmacao_v1, confirmacao_v2, etc. Assim você cria nova versão sem esperar.
phone_number_id — só waba_id. Se sua projeção chavear só por ID, você perde o evento em silêncio. Use (template_name, language) como chave dentro de uma WABA.
A mensagem é cobrada pela Meta direto da conta de WhatsApp Business do cliente final.
Cenários:
131042. Não é problema da sua API — é do cliente.131042 novamente. O cliente precisa recarregar.Em Coexistência, há dois tipos de outbound (mensagens saindo):
| Tipo | origin | Quem enviou? | Ação recomendada |
|---|---|---|---|
| Echo | BUSINESS_APP_ECHO | Alguém respondeu pelo celular (app WhatsApp Business) | Registrar no CRM, não enviar para IA |
| Sent | CLOUD_API | Você enviou via API | Registrar como "seu" |
Sem filtrar echo, sua IA pode responder a uma resposta que o próprio time deu pelo celular — criando loop.
// ERRADO: sem filtro
if (event.event === 'whatsapp.message.received') {
await aiService.respond(event.data); // Vai responder ao echo também!
}
// CERTO: filtra echo
if (event.event === 'whatsapp.message.received' &&
event.data.origin !== 'BUSINESS_APP_ECHO') {
await aiService.respond(event.data); // Só mensagens reais do cliente
}
| Status | Significado |
|---|---|
CONNECTED | Tudo ok. Pode enviar e receber. |
DEGRADED | Conectado mas com aviso (ex: webhook não registrado). Funciona, mas incompleto. |
REVOKED | Cliente revogou permissão no Gerenciador de Negócios da Meta. Não funciona mais — avise o cliente. |
Cada conta WhatsApp Business tem teto de templates. Limite padrão: 250 por idioma.
Quando atinge o limite, novos templates ficam em LIMIT_EXCEEDED e não podem ser enviados.
template_v1, template_v2.
Toda mensagem que VZD envia para seu webhook está assinada com HMAC-SHA256.
X-VZD-Signaturesha256=<hash_hex>Sempre valide a assinatura antes de processar. É a única forma de garantir que veio da VZD e não de um atacante.
JSON.stringify(request.body) para re-validar, a ordem de chaves e espaçamento podem mudar. Use sempre o corpo bruto original.
Se VZD não receber confirmação (HTTP 200) rápido, reenvia o mesmo evento com o mesmo event_id.
Para não processar duplicatas:
event_id que processarevent_id é determinístico por evento — sempre o mesmo para a mesma mensagem.
Sua chave de API e seu segredo de webhook são cifrados em Postgres com AES-256-GCM.
Dump do banco não entrega suas credenciais — teria que quebrar a cifra.
Cada secret tem um ID de chave embutido no envelope (formato v2.k1.<iv>.<tag>.<ciphertext>), permitindo girar chaves sem parada de serviço.
| Limite | Escopo | Padrão |
|---|---|---|
| Envio de mensagens | Por canal (phone_number_id), por segundo | Confira documentação |
| Listagem de templates | Por canal, por minuto | 30 chamadas/min |
| Criação de sessão de conexão | Por tenant, por janela | Confira documentação |
Se exceder, recebe HTTP 429 com header Retry-After: <segundos>.