/api/layer/meta) usando sua chave ps_, e os webhooks de chamada são re-entregues pelo Pilot Status.
Requisitos
- Chatwoot self-hosted ≥ v4.15 (o canal de voz é um recurso enterprise; o Chatwoot Cloud não é suportado — esta configuração precisa de uma variável de ambiente global).
- Uma instalação do Chatwoot dedicada, ou uma em que todas as inboxes WhatsApp Cloud usem uma chave
ps_do Pilot Status — o override de base URL abaixo é global. - Um número Meta Cloud API (oficial) no Pilot Status com chamadas habilitadas e tier de mensagens ≥ 2 mil. Números não oficiais (web) não são suportados pelo canal de voz do Chatwoot — use o softphone do Pilot Status para eles.
- A chave
ps_com escopo de número (Perfil → API), mais o Phone Number ID, o WABA ID e o Business Account ID do número — todos copiáveis no card do número na página Números.
Passo 1 — Aponte o Chatwoot para a camada Meta do Pilot Status
Adicione ao ambiente dos containers Rails e Sidekiq e reinicie:Passo 2 — Crie uma inbox WhatsApp Cloud manual
No Chatwoot: Settings → Inboxes → Add Inbox → WhatsApp → WhatsApp Cloud (manual/API, não o Embedded Signup):| Campo | Valor |
|---|---|
| Phone number | O número em E.164 com+ (ex.: +15551234567) |
| Phone number ID | O Meta Phone ID do número |
| Business Account ID | O WABA ID do número |
| API key | A chave ps_ do número |
?access_token=ps_…), que a camada do Pilot Status aceita e remove antes de encaminhar (sua chave ps_ nunca chega à Meta).
Após a criação, o Chatwoot tenta registrar seu webhook diretamente no
graph.facebook.com (a URL é fixa no código upstream), recebe 401 e mostra um banner de “reauthorization required”. É apenas cosmético — o Passo 3 o limpa.Passo 3 — Habilite a voz na conta e no canal
O caminho de voz do Chatwoot exige três coisas: o recurso de contachannel_voice, a flag de canal calling_enabled e um provider whatsapp_cloud. O toggle da UI (inbox → Calls → Enable Voice Calling) não consegue definir a flag nesta configuração — ele também chama a URL fixa do Graph e falha com 401 antes de persistir. Habilite pelo console Rails:
Sem acesso a shell? Rode de forma idempotente no boot (docker compose)
Sem acesso a shell? Rode de forma idempotente no boot (docker compose)
Se você não consegue abrir um console no host (plataformas gerenciadas), rode o mesmo script a cada boot do serviço Procure por
rails — ele é no-op depois de aplicado. Base64 evita problemas de aspas nos validadores de compose:voice-setup ok (ou voice-setup skipped: <motivo>) nos logs do rails após o deploy.Passo 4 — Entregue os webhooks de chamada a partir do Pilot Status
Crie um webhook com escopo do número assinando apenas o eventocalls, apontando para o endpoint de webhook da inbox (o telefone na URL deve corresponder exatamente ao phone_number do canal, incluindo o +):
- Não defina um
secret— a verificação de assinatura é dispensada para inboxes manuais sem app secret, e é exatamente isso que faz a re-entrega do Pilot Status funcionar. - Assine apenas
["calls"]. Adicionarmessagesduplicaria toda mensagem recebida se o número também usar o espelhamento padrão do Chatwoot. - O Pilot Status entrega o envelope da Meta na íntegra (
entry[].changes[]de mudança única comfield: "calls"), que é exatamente o formato que o job de eventos de WhatsApp do Chatwoot espera.
Passo 5 — Teste
- Recebida (usuário liga para a empresa): ligue para o número de um celular → um banner de chamada toca na inbox do Chatwoot → atenda no navegador → áudio bidirecional → desligue; a chamada fica registrada na conversa.
- Realizada (agente liga para o usuário): exige a permissão de chamada do usuário (a Meta bloqueia com o erro
138006sem ela) e um método de pagamento na WABA (erro131044sem ele). Veja Chamadas de Voz — permissões.
Limitações e observações
- Latência de sinalização — a perna do webhook passa pela entrega do Pilot Status antes do Sidekiq do Chatwoot. A janela de toque da Meta é de ~30s; fique atento a toques atrasados sob carga.
- Caminho do áudio — WebRTC entre o navegador do agente e a Meta diretamente. Redes corporativas que bloqueiam UDP conectam a chamada mas produzem silêncio; isso está fora do controle do Chatwoot e do Pilot Status.
- Respostas de permissão de chamada são entregues no campo
messages, não emcalls, então o estado de permissão do Chatwoot não é atualizado automaticamente nesta configuração. Chamadas realizadas sem permissão falham com um138006legível. - As configurações são compartilhadas — tanto o Pilot Status (chamadas habilitadas por padrão) quanto o Chatwoot escrevem no mesmo objeto
/settingsda Meta; a última escrita vence. - O softphone /chat do Pilot Status continua funcionando em paralelo — mas apenas uma superfície deve atender uma determinada chamada.