Appearance
Regras WhatsApp & Meta API
Janela de 24 horas (regra da Meta)
Após o cliente enviar uma mensagem, o sistema tem 24 horas para responder livremente com qualquer conteúdo.
Fora dessa janela, só é possível enviar templates aprovados pela Meta (status = 'APPROVED').
No código: O sistema fecha conversas automaticamente 30 minutos antes do fim da janela (23h30), aplicando a label conversa_expirada. Isso evita que mensagens livres sejam enviadas e falhem.
Exceção: Grace period de 2h após a mensagem de boas-vindas ao cliente que estava aguardando reabertura da loja — evita fechar a conversa imediatamente.
Tiers de taxa de mensagem Meta
Cada número WhatsApp Business tem um tier que limita mensagens por 24h:
| Tier | Limite (24h) |
|---|---|
| TIER_50 | 250 mensagens |
| TIER_250 | 2.000 mensagens |
| TIER_1K | 10.000 mensagens |
| TIER_10K | 100.000 mensagens |
| TIER_100K / UNLIMITED | Sem limite |
O tier atual é consultado antes de cada disparo de campanha. O frontend mostra aviso se a campanha vai exceder o tier.
Fallback de tier: Se messaging_limit_tier não estiver disponível, usa throughput: STANDARD → TIER_250, HIGH → TIER_1K, NOT_SET → TIER_50.
Opt-out e opt-in
Opt-out (cliente quer parar de receber)
Padrão de texto detectado (case-insensitive):
pare | parar | stop | sair | cancelar | descadastrar | não queroQuando detectado:
- Define
whatsappOptOut = trueno cliente - Envia mensagem de confirmação configurada em
optOutMessage - Campanha nunca mais envia para este cliente
Opt-in (cliente volta a aceitar)
Padrão de texto detectado:
voltar | recadastrar | receber | quero | continuar | cadastrarQuando detectado:
- Define
whatsappOptOut = falseno cliente - Cliente volta a receber campanhas
Opt-out via botão de template
Botões marcados como isUnsubscribe: true nos templates CRM:
- Geram token permanente de opt-out por cliente
- URL:
/go/unsubscribe/{token} - Define
whatsappOptOut = truepermanentemente - Não tem como reverter automaticamente (só manualmente)
Tipos de template
| Categoria | Uso | Custo |
|---|---|---|
MARKETING | Campanhas promocionais, novidades | Mais caro |
UTILITY | Confirmações, alertas de pedido | Intermediário |
AUTHENTICATION | OTPs, verificação | Mais barato |
O CRM usa principalmente MARKETING e UTILITY.
Status de template
| Status | Significado | Pode enviar? |
|---|---|---|
DRAFT | Salvo localmente, não enviado à Meta | Não |
PENDING | Enviado à Meta, aguardando revisão | Não |
APPROVED | Aprovado pela Meta | Sim |
REJECTED | Rejeitado pela Meta | Não |
PAUSED | Pausado pela Meta (qualidade baixa) | Não |
Regras de edição de template
- Template em rascunho (DRAFT): pode alterar tudo
- Template aprovado (APPROVED):
- Não pode mudar quantidade ou tipo de botões
- Salva
hasDraftChanges = truelocalmente - Para mudar botões: criar novo template
- Error
#2388024(nome já existe no Meta): o sistema vincula ao template existente automaticamente
Deduplicação de mensagens inbound
Cada mensagem recebida tem um wamId único. O sistema usa Redis (TTL 5 min) para evitar processar a mesma mensagem duas vezes — a Meta pode enviar webhooks duplicados.
Reconciliação de status (a cada 15 min)
O ReconciliationService verifica mensagens nos últimos 24h com status pendente (SENT/DELIVERED) e consulta o Chatwoot para atualizar o status real. Se uma mensagem teve clique registrado mas não teve delivered, considera como entregue (clique é prova irrefutável de entrega).
Variáveis em templates WhatsApp
Variáveis no corpo do template são representadas como 1, 2, etc.
O CRM usa um variableMapping para mapear posição → campo:
| Mapping | Valor usado |
|---|---|
first_name | Primeiro nome do cliente (fallback: "Cliente") |
name | Nome completo (fallback: "Cliente") |
seller_name | Vendedor da última compra (fallback: "Nossa equipe") |
store_name | Loja da última compra (fallback: nome da organização) |
__literal__:valor | Texto literal fixo |
__REDIRECT_URL__ | Substituído pela URL de tracking no envio |
Regra crítica: Se qualquer variável resolver como string vazia, o job falha com erro e não é enviado (a Meta retorna erro #131008 para variáveis vazias).