Como construímos um CRM jurídico com WhatsApp como canal principal
Um escritório de advocacia com 15 advogados, cada um com o próprio celular, cada um atendendo clientes pelo WhatsApp pessoal. Contratos em pasta compartilhada no Drive. Status de processos em planilha que ninguém atualizava. Esse era o estado da Adele antes de começarmos.

[ o problema real ]
O cliente ligava para o escritório perguntando sobre o processo. Ninguém sabia responder sem ligar para o advogado responsável. O advogado responsável estava em audiência. O cliente ficava sem resposta por horas.
O problema não era tecnologia. Era que cada advogado operava como uma ilha. O CRM ia ter que mudar esse comportamento sem exigir que ninguém mudasse de ferramenta — porque ninguém ia mudar de ferramenta.
[ a decisão central ]
WhatsApp Cloud API não como integração — como canal principal. Isso muda tudo.
Integração significa que você tem um sistema e o WhatsApp é uma saída. Canal principal significa que o WhatsApp é onde o atendimento acontece de verdade, e o sistema é o que organiza o que está chegando lá.
Escolhemos FastAPI + SQLModel no backend porque precisávamos de validação de schema rigorosa nos dados de processo. Cada mensagem recebida passa por um parser que tenta classificá-la: é sobre qual processo? É de qual cliente? É uma dúvida ou uma atualização?
O frontend em React ficou para o escritório — painel de casos, histórico de conversa por cliente, atribuição de responsável. O advogado continua respondendo pelo WhatsApp. O sistema apenas organiza o que está acontecendo.
# Classifier simplificado — versão de produção tem 3x mais regras
async def classify_message(msg: IncomingMessage) -> Classification:
client = await db.get_client_by_phone(msg.from_number)
if not client:
return Classification(type="unknown_sender")
open_cases = await db.get_open_cases(client.id)
if len(open_cases) == 1:
return Classification(
type="case_update",
case_id=open_cases[0].id,
confidence=0.91
)
# múltiplos casos abertos — precisa de contexto adicional
return Classification(type="ambiguous", client_id=client.id)
Classificação de mensagem — determina qual processo a mensagem pertence
[ o que ninguém documenta ]
Webhook reliability. A documentação do WhatsApp Cloud API é clara sobre o formato. O que ela não conta é que o mesmo webhook pode chegar duas vezes. Ou não chegar.
Implementamos idempotency por message ID antes de qualquer outra coisa. Cada mensagem processada é registrada. Duplicata descartada silenciosamente. Sem isso, um cliente receberia duas respostas automáticas e um caso seria registrado em duplicidade.
O segundo problema: múltiplos advogados no mesmo caso. Se dois advogados respondem ao cliente com 30 segundos de diferença, qual resposta o cliente vê primeiro? Qual a ordem no histórico? Adicionamos timestamp de envio real (não de recebimento pelo nosso server) e ordenação explícita na query.
"A lição central: quando o canal de comunicação já é o WhatsApp, o sistema precisa ir até lá — não o contrário. Qualquer CRM que exige que o advogado mude de ferramenta vai falhar na adoção. O que funciona é o sistema que se adapta ao comportamento existente."
Tem um problema parecido na sua operação?
outros artigos