n8n + EvolutionAPI + OpenAI · stack completa
Tutorial completo para colocar um agente IA respondendo no WhatsApp em uma tarde — do servidor ao primeiro lead, com n8n, EvolutionAPI e OpenAI.
A combinação n8n + EvolutionAPI + OpenAI é a stack mais usada no Brasil para agente IA no WhatsApp. Este guia leva você do servidor recém-provisionado ao primeiro lead respondido — sem pular etapas que costumam quebrar em produção.
TL;DR
- Tempo total: ~2 horas (sem distração)
- Custo de servidor: a partir de R$ 79/mês (VPS Pro)
- Custo OpenAI: ~R$ 0,04 por conversa de 10 mensagens (gpt-4o-mini)
- Resultado: WhatsApp respondendo automaticamente com base no que você definir
O que você vai precisar
Pré-requisitos
- Uma VPS com Docker (recomendamos VPS Pro)
- Domínio próprio (
automacao.sua-empresa.com.br) - Token OpenAI (ou Anthropic Claude — o setup é igual)
- Número WhatsApp não pessoal (use chip dedicado)
Arquitetura
WhatsApp ──▶ EvolutionAPI ──webhook──▶ n8n ──▶ OpenAI ──▶ resposta
▲ │
└──── envio de mensagem ─────────────────────┘
Cada peça em seu container Docker, atrás de um único reverse proxy (Caddy ou Traefik) que cuida do HTTPS.
Passo 1 — provisionar a VPS
Após contratar o servidor, você recebe um e-mail de boas-vindas com endereço, porta SSH, usuário e senha. Use exatamente os valores do e-mail.
Conectado, crie um usuário não-root e instale Docker:
adduser deploy
usermod -aG sudo deploy
su - deploy
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker deploy
exit
Reentre como deploy (mesmo comando do e-mail, trocando o usuário):
docker --version
Passo 2 — apontar DNS
No seu registrador (Registro.br, Cloudflare, etc), crie 2 subdomínios apontando para o IP da VPS:
| Tipo | Nome | Valor |
|---|---|---|
| A | n8n | IP da VPS |
| A | evo | IP da VPS |
Aguarde até 30 minutos para propagar. Confirme com:
dig n8n.sua-empresa.com.br +short
dig evo.sua-empresa.com.br +short
Ambos devem retornar o IP da VPS.
Passo 3 — docker-compose
Crie a pasta do projeto:
mkdir -p ~/stack-ia && cd ~/stack-ia
Gere uma chave de criptografia para o n8n:
openssl rand -hex 32
Salve o output — você vai colocar em N8N_ENCRYPTION_KEY.
Crie ~/stack-ia/.env:
DOMAIN_BASE=sua-empresa.com.br
N8N_ENCRYPTION_KEY=cole_aqui_o_hex_de_64_caracteres
EVOLUTION_API_KEY=defina_uma_string_secreta_grande
POSTGRES_PASSWORD=outra_string_secreta
Crie ~/stack-ia/docker-compose.yml:
services:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: rollin
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: postgres
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "rollin"]
interval: 10s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
evolution-api:
image: atendai/evolution-api:v2
restart: unless-stopped
environment:
AUTHENTICATION_API_KEY: ${EVOLUTION_API_KEY}
DATABASE_ENABLED: "true"
DATABASE_PROVIDER: postgresql
DATABASE_CONNECTION_URI: postgresql://rollin:${POSTGRES_PASSWORD}@postgres:5432/evolution?schema=public
DATABASE_SAVE_DATA_INSTANCE: "true"
DATABASE_SAVE_DATA_NEW_MESSAGE: "true"
DATABASE_SAVE_MESSAGE_UPDATE: "true"
CACHE_REDIS_ENABLED: "true"
CACHE_REDIS_URI: redis://redis:6379/2
SERVER_URL: https://evo.${DOMAIN_BASE}
depends_on:
postgres:
condition: service_healthy
n8n:
image: docker.n8n.io/n8nio/n8n
restart: unless-stopped
environment:
N8N_HOST: n8n.${DOMAIN_BASE}
N8N_PROTOCOL: https
WEBHOOK_URL: https://n8n.${DOMAIN_BASE}/
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_USER: rollin
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
DB_POSTGRESDB_DATABASE: n8n
EXECUTIONS_PROCESS: main
GENERIC_TIMEZONE: America/Sao_Paulo
depends_on:
postgres:
condition: service_healthy
volumes:
pg_data:
caddy_data:
caddy_config:
Crie ~/stack-ia/Caddyfile:
n8n.sua-empresa.com.br {
reverse_proxy n8n:5678
}
evo.sua-empresa.com.br {
reverse_proxy evolution-api:8080
}
Substitua sua-empresa.com.br pelo seu domínio real.
Crie os bancos no Postgres antes de subir:
docker compose up -d postgres
sleep 10
docker compose exec postgres psql -U rollin -c "CREATE DATABASE n8n;"
docker compose exec postgres psql -U rollin -c "CREATE DATABASE evolution;"
Suba todo o resto:
docker compose up -d
docker compose logs -f
Aguarde o Caddy emitir o SSL (30-60s). Acesse:
https://n8n.sua-empresa.com.br→ tela de signup do n8nhttps://evo.sua-empresa.com.br→ JSON{"status":200,...}
Passo 4 — criar instância na EvolutionAPI
curl -X POST https://evo.sua-empresa.com.br/instance/create \
-H "Content-Type: application/json" \
-H "apikey: SEU_EVOLUTION_API_KEY" \
-d '{
"instanceName": "atendimento",
"qrcode": true,
"integration": "WHATSAPP-BAILEYS"
}'
A resposta inclui qrcode.base64. Decode e escaneie no WhatsApp:
echo "BASE64_AQUI" | base64 -d > qr.png
Baixe qr.png para sua máquina e abra. No WhatsApp do celular: Aparelhos conectados → Conectar aparelho e escaneie.
Confirme que conectou:
curl https://evo.sua-empresa.com.br/instance/connectionState/atendimento \
-H "apikey: SEU_EVOLUTION_API_KEY"
Espere ver "state":"open".
Passo 5 — workflow no n8n
Acesse https://n8n.sua-empresa.com.br, crie sua conta admin e siga os passos abaixo.
5.1 — adicionar nó Webhook
Novo workflow → Webhook com:
- HTTP Method:
POST - Path:
whats-in-atendimento - Response Mode:
Immediately
Salve e copie a Production URL (algo como https://n8n.sua-empresa.com.br/webhook/whats-in-atendimento).
5.2 — configurar webhook na EvolutionAPI
curl -X POST https://evo.sua-empresa.com.br/webhook/set/atendimento \
-H "Content-Type: application/json" \
-H "apikey: SEU_EVOLUTION_API_KEY" \
-d '{
"webhook": {
"enabled": true,
"url": "https://n8n.sua-empresa.com.br/webhook/whats-in-atendimento",
"events": ["MESSAGES_UPSERT"],
"webhookByEvents": false
}
}'
Mande uma mensagem de teste para o número conectado e veja chegar no n8n. O payload tem o texto em body.data.message.conversation.
5.3 — filtro IF
Adicione um nó IF com:
- Condição 1:
{{ $json.body.data.key.fromMe }}isfalse(ignora mensagens enviadas por você) - Condição 2:
{{ $json.body.data.message.conversation }}is not empty
5.4 — nó OpenAI Chat Model
- Credential: criar com seu token OpenAI
- Model:
gpt-4o-mini - Messages:
System: Você é o atendente da Rollin Host. Responda em português,
em 2-3 frases curtas. Se a pergunta for sobre preço, redirecione para
https://www.rollinhost.com.br/calculadora-economia-com-ia
User: {{ $json.body.data.message.conversation }}
5.5 — nó HTTP Request para enviar resposta
- Method:
POST - URL:
https://evo.sua-empresa.com.br/message/sendText/atendimento - Headers:
apikey:SEU_EVOLUTION_API_KEYContent-Type:application/json
- Body (JSON):
{
"number": "{{ $('Webhook').item.json.body.data.key.remoteJid }}",
"text": "{{ $json.choices[0].message.content }}"
}
5.6 — ativar
Ative o workflow (toggle no canto superior direito).
Passo 6 — testar de ponta a ponta
Mande uma mensagem para o número WhatsApp conectado. Em ~3-5 segundos, você recebe a resposta gerada.
Se não funcionar, debug pela ordem:
- EvolutionAPI recebeu? →
docker compose logs evolution-api - Webhook chegou no n8n? → veja Executions no n8n (deve aparecer)
- OpenAI respondeu? → abra a execution e veja o payload do nó OpenAI
- Envio falhou? → veja status do HTTP Request — se
400, onumberestá errado (deve incluir DDD+país sem+, terminando em@s.whatsapp.netse usado direto)
Passo 7 — produção: lembre-se disso
Como o custo se comporta
Por conversa típica (10 mensagens, ~500 tokens entrada + 200 saída com gpt-4o-mini):
- Entrada: 500 × R$ 0,00075 / 1k = R$ 0,00038
- Saída: 200 × R$ 0,003 / 1k = R$ 0,0006
- Total por conversa: ~R$ 0,001
Em 1.000 conversas/mês = R$ 1. A VPS é a maior parte do custo.
Próximos passos
Conectar mais números
Trocar OpenAI por LLM próprio
Adicionar memória ao agente
Escalar para alto volume
Última atualização: