Migração 100% grátis na contratação semestral · nossa equipe migra tudo de qualquer provedor · novos clientes Migrar agora
Agente de IA no WhatsApp na API Oficial da Meta · somos Tech Provider aprovado · orçamento sob consulta Pedir orçamento
VPS com OpenClaw pré-instalado · a partir de R$ 56,90/mês · gerenciada pela Rollin Quero a VPS
VPS com Hermes Agent pré-instalado · a partir de R$ 56,90/mês · gerenciada pela Rollin Quero a VPS
Hospedagem com 30 dias de garantia · Não gostou? Devolvemos 100%, sem perguntas. Ver hospedagem

n8n + EvolutionAPI + OpenAI · full stack

Complete tutorial to get an AI agent answering on WhatsApp in one afternoon, from the server to your first lead, with n8n, EvolutionAPI and OpenAI.

The n8n + EvolutionAPI + OpenAI combination is the most widely used stack in Brazil for AI agents on WhatsApp. This guide takes you from a freshly provisioned server to your first answered lead, without skipping the steps that tend to break in production.

TL;DR

  • Total time: ~2 hours (without distractions)
  • Server cost: from R$ 79/month (VPS Pro)
  • OpenAI cost: ~R$ 0,04 per 10-message conversation (gpt-4o-mini)
  • Result: WhatsApp replying automatically based on whatever you define

What you will need

Prerequisites

  • A VPS with Docker (we recommend VPS Pro)
  • Your own domain (automacao.sua-empresa.com.br)
  • An OpenAI token (or Anthropic Claude, the setup is the same)
  • A non-personal WhatsApp number (use a dedicated SIM)

Architecture

WhatsApp ──▶ EvolutionAPI ──webhook──▶ n8n ──▶ OpenAI ──▶ reply
                  ▲                                            │
                  └──── message sending ───────────────────────┘

Each piece runs in its own Docker container, behind a single reverse proxy (Caddy or Traefik) that handles HTTPS.

Step 1: provision the VPS

After ordering the server, you receive a welcome email with the address, SSH port, username and password. Use exactly the values from the email.

Once connected, create a non-root user and install Docker:

adduser deploy
usermod -aG sudo deploy
su - deploy

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker deploy
exit

Log back in as deploy (same command from the email, changing the user):

docker --version

Step 2: point DNS

At your registrar (Registro.br, Cloudflare, etc.), create 2 subdomains pointing to the VPS IP:

TypeNameValue
An8nVPS IP
AevoVPS IP

Allow up to 30 minutes for propagation. Confirm with:

dig n8n.sua-empresa.com.br +short
dig evo.sua-empresa.com.br +short

Both should return the VPS IP.

Step 3: docker-compose

Create the project folder:

mkdir -p ~/stack-ia && cd ~/stack-ia

Generate an encryption key for n8n:

openssl rand -hex 32

Save the output: you will put it in N8N_ENCRYPTION_KEY.

Create ~/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

Create ~/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:

Create ~/stack-ia/Caddyfile:

n8n.sua-empresa.com.br {
  reverse_proxy n8n:5678
}

evo.sua-empresa.com.br {
  reverse_proxy evolution-api:8080
}

Replace sua-empresa.com.br with your real domain.

Create the databases in Postgres before bringing everything up:

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;"

Bring up everything else:

docker compose up -d
docker compose logs -f

Wait for Caddy to issue SSL (30-60s). Then open:

  • https://n8n.sua-empresa.com.br → n8n signup screen
  • https://evo.sua-empresa.com.br → JSON {"status":200,...}

Step 4: create the instance in 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"
  }'

The response includes qrcode.base64. Decode it and scan it in WhatsApp:

echo "BASE64_AQUI" | base64 -d > qr.png

Download qr.png to your machine and open it. In WhatsApp on your phone: Linked devices → Link a device and scan it.

Confirm it connected:

curl https://evo.sua-empresa.com.br/instance/connectionState/atendimento \
  -H "apikey: SEU_EVOLUTION_API_KEY"

You should see "state":"open".

Step 5: workflow in n8n

Go to https://n8n.sua-empresa.com.br, create your admin account and follow the steps below.

5.1: add the Webhook node

New workflow → Webhook with:

  • HTTP Method: POST
  • Path: whats-in-atendimento
  • Response Mode: Immediately

Save and copy the Production URL (something like https://n8n.sua-empresa.com.br/webhook/whats-in-atendimento).

5.2: configure the webhook in 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
    }
  }'

Send a test message to the connected number and watch it arrive in n8n. The payload carries the text in body.data.message.conversation.

5.3: IF filter

Add an IF node with:

  • Condition 1: {{ $json.body.data.key.fromMe }} is false (ignores messages sent by you)
  • Condition 2: {{ $json.body.data.message.conversation }} is not empty

5.4: OpenAI Chat Model node

  • Credential: create it with your OpenAI token
  • 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: HTTP Request node to send the reply

  • Method: POST
  • URL: https://evo.sua-empresa.com.br/message/sendText/atendimento
  • Headers:
    • apikey: SEU_EVOLUTION_API_KEY
    • Content-Type: application/json
  • Body (JSON):
{
  "number": "{{ $('Webhook').item.json.body.data.key.remoteJid }}",
  "text": "{{ $json.choices[0].message.content }}"
}

5.6: activate

Activate the workflow (toggle in the top right corner).

Step 6: test end to end

Send a message to the connected WhatsApp number. Within ~3-5 seconds, you receive the generated reply.

If it does not work, debug in this order:

  1. Did EvolutionAPI receive it? → docker compose logs evolution-api
  2. Did the webhook reach n8n? → check Executions in n8n (it should show up)
  3. Did OpenAI respond? → open the execution and check the OpenAI node payload
  4. Did sending fail? → check the HTTP Request status: if it is 400, the number is wrong (it must include area code + country code without +, ending in @s.whatsapp.net if used directly)

Step 7: production, keep this in mind

How the cost behaves

Per typical conversation (10 messages, ~500 input tokens + 200 output with gpt-4o-mini):

  • Input: 500 × R$ 0,00075 / 1k = R$ 0,00038
  • Output: 200 × R$ 0,003 / 1k = R$ 0,0006
  • Total per conversation: ~R$ 0,001

At 1.000 conversations/month = R$ 1. The VPS is most of the cost.

Next steps

Last updated: