n8n + EvolutionAPI + OpenAI · stack completo
Tutorial completo para poner un agente de IA a responder en WhatsApp en una tarde, del servidor al primer lead, con n8n, EvolutionAPI y OpenAI.
La combinación n8n + EvolutionAPI + OpenAI es el stack más usado en Brasil para agentes de IA en WhatsApp. Esta guía te lleva del servidor recién aprovisionado al primer lead respondido, sin saltarse las etapas que suelen romperse en producción.
TL;DR
- Tiempo total: ~2 horas (sin distracciones)
- Costo del servidor: desde R$ 79/mes (VPS Pro)
- Costo de OpenAI: ~R$ 0,04 por conversación de 10 mensajes (gpt-4o-mini)
- Resultado: WhatsApp respondiendo automáticamente según lo que tú definas
Lo que vas a necesitar
Requisitos previos
- Un VPS con Docker (recomendamos VPS Pro)
- Dominio propio (
automacao.sua-empresa.com.br) - Token de OpenAI (o Anthropic Claude, la configuración es igual)
- Número de WhatsApp no personal (usa un chip dedicado)
Arquitectura
WhatsApp ──▶ EvolutionAPI ──webhook──▶ n8n ──▶ OpenAI ──▶ respuesta
▲ │
└──── envío de mensaje ──────────────────────┘
Cada pieza en su propio contenedor Docker, detrás de un único reverse proxy (Caddy o Traefik) que se encarga del HTTPS.
Paso 1: aprovisionar el VPS
Después de contratar el servidor, recibes un correo de bienvenida con dirección, puerto SSH, usuario y contraseña. Usa exactamente los valores del correo.
Una vez conectado, crea un usuario no root e instala Docker:
adduser deploy
usermod -aG sudo deploy
su - deploy
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker deploy
exit
Vuelve a entrar como deploy (el mismo comando del correo, cambiando el usuario):
docker --version
Paso 2: apuntar el DNS
En tu registrador (Registro.br, Cloudflare, etc.), crea 2 subdominios apuntando a la IP del VPS:
| Tipo | Nombre | Valor |
|---|---|---|
| A | n8n | IP del VPS |
| A | evo | IP del VPS |
Espera hasta 30 minutos a que se propague. Confírmalo con:
dig n8n.sua-empresa.com.br +short
dig evo.sua-empresa.com.br +short
Ambos deben devolver la IP del VPS.
Paso 3: docker-compose
Crea la carpeta del proyecto:
mkdir -p ~/stack-ia && cd ~/stack-ia
Genera una clave de cifrado para n8n:
openssl rand -hex 32
Guarda la salida: la vas a colocar en N8N_ENCRYPTION_KEY.
Crea ~/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
Crea ~/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:
Crea ~/stack-ia/Caddyfile:
n8n.sua-empresa.com.br {
reverse_proxy n8n:5678
}
evo.sua-empresa.com.br {
reverse_proxy evolution-api:8080
}
Reemplaza sua-empresa.com.br por tu dominio real.
Crea las bases de datos en Postgres antes de levantar todo:
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;"
Levanta todo lo demás:
docker compose up -d
docker compose logs -f
Espera a que Caddy emita el SSL (30-60s). Accede a:
https://n8n.sua-empresa.com.br→ pantalla de registro de n8nhttps://evo.sua-empresa.com.br→ JSON{"status":200,...}
Paso 4: crear la instancia en 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"
}'
La respuesta incluye qrcode.base64. Decodifícalo y escanéalo en WhatsApp:
echo "BASE64_AQUI" | base64 -d > qr.png
Descarga qr.png a tu máquina y ábrelo. En WhatsApp del celular: Dispositivos vinculados → Vincular dispositivo y escanéalo.
Confirma que se conectó:
curl https://evo.sua-empresa.com.br/instance/connectionState/atendimento \
-H "apikey: SEU_EVOLUTION_API_KEY"
Deberías ver "state":"open".
Paso 5: workflow en n8n
Accede a https://n8n.sua-empresa.com.br, crea tu cuenta de administrador y sigue los pasos a continuación.
5.1: agregar el nodo Webhook
Nuevo workflow → Webhook con:
- HTTP Method:
POST - Path:
whats-in-atendimento - Response Mode:
Immediately
Guarda y copia la Production URL (algo como https://n8n.sua-empresa.com.br/webhook/whats-in-atendimento).
5.2: configurar el webhook en 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
}
}'
Envía un mensaje de prueba al número conectado y observa cómo llega a n8n. El payload trae el texto en body.data.message.conversation.
5.3: filtro IF
Agrega un nodo IF con:
- Condición 1:
{{ $json.body.data.key.fromMe }}isfalse(ignora los mensajes enviados por ti) - Condición 2:
{{ $json.body.data.message.conversation }}is not empty
5.4: nodo OpenAI Chat Model
- Credential: créala con tu token de 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: nodo HTTP Request para enviar la respuesta
- 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: activar
Activa el workflow (toggle en la esquina superior derecha).
Paso 6: probar de punta a punta
Envía un mensaje al número de WhatsApp conectado. En ~3-5 segundos, recibes la respuesta generada.
Si no funciona, depura en este orden:
- ¿EvolutionAPI lo recibió? →
docker compose logs evolution-api - ¿El webhook llegó a n8n? → revisa Executions en n8n (debe aparecer)
- ¿OpenAI respondió? → abre la execution y revisa el payload del nodo OpenAI
- ¿Falló el envío? → revisa el status del HTTP Request: si es
400, elnumberestá mal (debe incluir código de área + país sin+, terminando en@s.whatsapp.netsi se usa directamente)
Paso 7: producción, tenlo en cuenta
Cómo se comporta el costo
Por conversación típica (10 mensajes, ~500 tokens de entrada + 200 de salida con gpt-4o-mini):
- Entrada: 500 × R$ 0,00075 / 1k = R$ 0,00038
- Salida: 200 × R$ 0,003 / 1k = R$ 0,0006
- Total por conversación: ~R$ 0,001
En 1.000 conversaciones/mes = R$ 1. El VPS es la mayor parte del costo.
Próximos pasos
Conectar más números
Cambiar OpenAI por un LLM propio
Agregar memoria al agente
Escalar a alto volumen
Última actualización: