Integração Evolution API
Provider de WhatsApp para clientes Kommo. Self-hosted, free, alta flexibilidade.
O que é Evolution API
API REST que se conecta ao WhatsApp via Baileys (biblioteca não-oficial). Permite:
- Múltiplas instâncias (uma por tenant)
- Envio e recepção de mensagens, mídia, status
- Webhooks para eventos
- Controle de conexão via QR code
Trade-off: não é oficial WhatsApp Business API. Risco de banimento se mal configurado. Aceitável para volumes moderados.
Hosting
Triadeflow hospeda própria instância de Evolution em Hetzner:
- URL:
https://evolution.triadeflow.com - API Key global em vault
- Cada tenant tem instância isolada
Operações principais
Criar instância
from triadeflow_core.messaging.evolution import EvolutionProvider
provider = EvolutionProvider( base_url="https://evolution.triadeflow.com", api_key=settings.evolution_api_key,)
await provider.create_instance( instance_name=f"{tenant_id}-prod", webhook_url=f"https://{agent_type}.triadeflow.com/webhook/{tenant_id}", webhook_events=["MESSAGES_UPSERT", "CONNECTION_UPDATE", "QRCODE_UPDATED"],)Conectar (QR code)
qr = await provider.get_qr(instance_name=f"{tenant_id}-prod")# Enviar QR code para o cliente escanear via WhatsApp WebCliente escaneia, instância fica connected. A partir daí, mensagens fluem.
Enviar mensagem de texto
await provider.send_text( instance_name=f"{tenant_id}-prod", to="5585999998888", text="Olá! Como posso ajudar?",)Enviar mídia
await provider.send_media( instance_name=f"{tenant_id}-prod", to="5585999998888", media_url="https://triadeflow.com/catalogo.pdf", caption="Catálogo completo", media_type="document",)Receber mensagem (webhook)
Evolution envia POST para webhook_url configurado. Payload:
{ "event": "messages.upsert", "instance": "usa-salus-prod", "data": { "key": { "remoteJid": "5585999998888@s.whatsapp.net", "fromMe": false, "id": "ABC123" }, "message": { "conversation": "Olá, quero saber sobre o serviço" }, "messageTimestamp": 1714867200, "pushName": "João da Silva" }}Handler no agente:
@app.post("/webhook/{tenant_id}")async def handle_webhook(tenant_id: str, payload: dict): if payload["event"] != "messages.upsert": return {"status": "ignored"}
if payload["data"]["key"]["fromMe"]: return {"status": "outbound, ignored"}
# Processa mensagem await process_incoming(tenant_id, payload)Boas práticas para evitar banimento
WhatsApp não oficial é vulnerável a banimentos. Reduzir risco:
Aquecimento
- Conta nova: limite primeiros 7 dias a 50 msg/dia
- Aumente progressivamente
- Use número verificado (Business)
Comportamento humano
- Não responda em <1 segundo (parece bot)
- Adicione delay aleatório entre 1-3s
- Use “digitando…” (presence)
Limites diários
limites: max_messages_per_day: 1000 max_messages_per_minute: 20 delay_between_messages_sec: [1, 3] # min, max aleatórioProteções automáticas
- Se receber
account_blockedouconnection_closerepetidos, pausar instância - Alerta no Telegram para Alex
Múltiplas instâncias por tenant
Caso de uso: tenant tem volume alto e quer dois números.
messaging: provider: evolution instances: - name: usa-salus-prod-1 role: primary - name: usa-salus-prod-2 role: secondary routing: round_robin # ou by_segmentMigração para WhatsApp Business API oficial
Quando cliente cresce e quer estabilidade total:
- Solicitar verificação Meta Business
- Onboarding API oficial via Meta Cloud ou BSP
- Manter Evolution em paralelo durante transição
- Migrar conversas históricas
Documentação detalhada em .claude/integrations/whatsapp-business-cloud.md (futura).
Erros comuns
Instância “disconnected” do nada
Geralmente celular reiniciou ou desconectou WhatsApp Web. Pedir ao cliente reconectar.
Mensagens não chegam no webhook
Verificar:
- URL acessível externamente (não localhost)
- HTTPS válido
- Eventos corretos configurados
- Rate limit do servidor não excedido
Mensagens duplicadas
Adicionar idempotency check usando data.key.id como deduplication key (Redis SET com TTL 5min).
Hospedagem alternativa
Se Triadeflow self-hosted estiver instável, alternativas:
- Evolution API hosted (paid SaaS)
- Z-API (provider brasileiro)
- WPPConnect (similar Evolution)
A interface WhatsAppProvider no core permite trocar implementação sem alterar código de domínio.
Versão: 1.0