📚 Série: Automação WhatsApp → Automação WhatsApp | Evolution API | Chatbot WhatsApp | API WhatsApp
O que é WhatsApp Bot Python?
WhatsApp bot Python é aplicação web (Flask/FastAPI) que integra Evolution API ou Twilio para receber mensagens WhatsApp via webhook, processar com lógica customizada (ChatGPT, banco dados, APIs externas) e responder automaticamente. Bot Python permite: atendimento 24/7, qualificação leads, consulta estoque, geração boletos, agendamento consultas, integração CRM/ERP = tudo programado sob medida vs plataformas no-code limitadas. Desenvolvimento completo (webhook + lógica + deploy) leva 4-8h vs 4 semanas com linguagens compiladas.
Diferença: Python permite IA avançada (ML models), integrações ilimitadas (qualquer API) e lógica negócio complexa impossível em plataformas drag-and-drop.
Arquitetura Bot Python WhatsApp
Stack Completo
WhatsApp → Evolution API → Webhook → Flask Server → Lógica Python → Response
↓
PostgreSQL
ChatGPT API
CRM APIs
Business Logic
Componentes:
-
Evolution API (WhatsApp gateway)
- Gerencia conexões WhatsApp
- Envia/recebe mensagens
- Webhook notificações
-
Flask Server (aplicação Python)
- Recebe webhooks
- Processa mensagens
- Envia respostas
-
PostgreSQL (banco dados)
- Histórico conversas
- Estado conversação
- Clientes/produtos
-
ChatGPT API (IA conversacional)
- Entender intenção
- Gerar respostas naturais
- Qualificar leads
-
APIs Externas (integrações)
- CRM (Pipedrive)
- Pagamentos (Stripe)
- Email (SendGrid)
Tutorial: Bot WhatsApp Python (Código Completo)
Passo 1: Setup Ambiente
# Criar projeto
mkdir whatsapp-bot-python
cd whatsapp-bot-python
# Virtual environment
python3 -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# Instalar dependências
pip install flask requests python-dotenv openai psycopg2-binary
requirements.txt:
flask==3.0.0
requests==2.31.0
python-dotenv==1.0.0
openai==1.6.1
psycopg2-binary==2.9.9
gunicorn==21.2.0
Passo 2: Estrutura Projeto
whatsapp-bot/
├── .env
├── app.py (servidor Flask)
├── config.py (configurações)
├── database.py (conexão PostgreSQL)
├── whatsapp.py (funções Evolution API)
├── chatgpt.py (integração OpenAI)
├── handlers.py (lógica atendimento)
└── requirements.txt
Passo 3: Configurações (.env)
# Evolution API
EVOLUTION_API_URL=https://evolution.seudominio.com
EVOLUTION_API_KEY=sua-chave-secreta-aqui
EVOLUTION_INSTANCE=cliente-atendimento
# OpenAI
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxx
# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/whatsapp_bot
# Flask
FLASK_SECRET_KEY=sua-chave-secreta-flask
FLASK_PORT=5000
Passo 4: Código Bot (app.py)
from flask import Flask, request, jsonify
from dotenv import load_dotenv
import os
import logging
from handlers import processar_mensagem
from database import init_database
load_dotenv()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY')
# Configurar logs
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Inicializar banco
init_database()
@app.route('/webhook/whatsapp', methods=['POST'])
def webhook_whatsapp():
"""
Recebe mensagens WhatsApp da Evolution API
"""
try:
data = request.get_json()
# Validar estrutura
if not data or 'data' not in data:
return jsonify({'error': 'Invalid payload'}), 400
# Extrair dados mensagem
event = data.get('event')
message_data = data.get('data', {})
# Filtrar apenas mensagens recebidas (não enviadas)
if event != 'messages.upsert':
return jsonify({'status': 'ignored'}), 200
# Ignorar mensagens do próprio bot
if message_data.get('key', {}).get('fromMe'):
return jsonify({'status': 'own message'}), 200
# Processar mensagem
processar_mensagem(message_data)
return jsonify({'status': 'success'}), 200
except Exception as e:
logger.error(f'Erro webhook: {str(e)}')
return jsonify({'error': str(e)}), 500
@app.route('/health', methods=['GET'])
def health_check():
"""
Health check endpoint
"""
return jsonify({
'status': 'healthy',
'service': 'WhatsApp Bot Python'
}), 200
if __name__ == '__main__':
port = int(os.getenv('FLASK_PORT', 5000))
app.run(host='0.0.0.0', port=port, debug=False)
Passo 5: Integração Evolution API (whatsapp.py)
import requests
import os
import logging
logger = logging.getLogger(__name__)
EVOLUTION_URL = os.getenv('EVOLUTION_API_URL')
API_KEY = os.getenv('EVOLUTION_API_KEY')
INSTANCE = os.getenv('EVOLUTION_INSTANCE')
def enviar_mensagem_texto(numero, texto):
"""
Envia mensagem texto para WhatsApp
Args:
numero: Número formato 5511999887766
texto: Mensagem texto
Returns:
bool: True se enviou com sucesso
"""
try:
url = f'{EVOLUTION_URL}/message/sendText/{INSTANCE}'
headers = {
'Content-Type': 'application/json',
'apikey': API_KEY
}
payload = {
'number': numero,
'textMessage': {
'text': texto
}
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
logger.info(f'Mensagem enviada para {numero}')
return True
except Exception as e:
logger.error(f'Erro enviar mensagem: {str(e)}')
return False
def enviar_mensagem_imagem(numero, url_imagem, caption=''):
"""
Envia imagem WhatsApp
"""
try:
url = f'{EVOLUTION_URL}/message/sendMedia/{INSTANCE}'
headers = {
'Content-Type': 'application/json',
'apikey': API_KEY
}
payload = {
'number': numero,
'mediaMessage': {
'mediatype': 'image',
'media': url_imagem,
'caption': caption
}
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return True
except Exception as e:
logger.error(f'Erro enviar imagem: {str(e)}')
return False
def buscar_contato(numero):
"""
Busca informações contato WhatsApp
"""
try:
url = f'{EVOLUTION_URL}/chat/findContact/{INSTANCE}'
headers = {'apikey': API_KEY}
params = {'number': numero}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
data = response.json()
return data.get('name', 'Cliente')
except Exception as e:
logger.error(f'Erro buscar contato: {str(e)}')
return 'Cliente'
Passo 6: Integração ChatGPT (chatgpt.py)
from openai import OpenAI
import os
import logging
logger = logging.getLogger(__name__)
client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
SYSTEM_PROMPT = """
Você é assistente virtual WhatsApp da empresa TechStore.
Informações importantes:
- Horário funcionamento: Seg-Sex 8h-18h, Sáb 9h-13h
- Produtos: Notebooks, celulares, acessórios
- Entrega: Todo Brasil (prazo 5-10 dias úteis)
- Pagamento: PIX, cartão crédito, boleto
Suas regras:
1. Seja breve (máximo 2-3 frases por mensagem)
2. Use emojis com moderação 😊
3. Sempre pergunte se resolveu dúvida
4. Se cliente quiser falar com vendedor, diga que vai transferir
5. NUNCA invente preços ou informações técnicas (diga "vou consultar")
Exemplos:
Cliente: "Quanto custa iPhone 15?"
Você: "Deixa eu consultar preço atualizado pra você! Um momento 😊"
Cliente: "Vocês entregam em São Paulo?"
Você: "Sim! Entregamos em todo Brasil. Prazo pra SP: 3-5 dias úteis 📦"
"""
def gerar_resposta(mensagem_usuario, historico_contexto=[]):
"""
Gera resposta usando ChatGPT
Args:
mensagem_usuario: Mensagem atual cliente
historico_contexto: Lista mensagens anteriores [{'role': 'user', 'content': '...'}]
Returns:
str: Resposta gerada
"""
try:
# Montar histórico conversa
messages = [{'role': 'system', 'content': SYSTEM_PROMPT}]
messages.extend(historico_contexto[-5:]) # Últimas 5 mensagens contexto
messages.append({'role': 'user', 'content': mensagem_usuario})
# Chamar API
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=messages,
temperature=0.7,
max_tokens=150
)
resposta = response.choices[0].message.content
logger.info(f'ChatGPT respondeu: {resposta[:50]}...')
return resposta
except Exception as e:
logger.error(f'Erro ChatGPT: {str(e)}')
return "Desculpe, tive um problema técnico. Pode repetir? 😅"
def detectar_intencao(mensagem):
"""
Detecta intenção mensagem (compra, suporte, info, etc)
"""
try:
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[
{
'role': 'system',
'content': '''
Detecte intenção da mensagem:
- preco: Cliente quer saber preço produto
- estoque: Cliente quer saber disponibilidade
- compra: Cliente quer comprar/fechar pedido
- suporte: Cliente tem problema/reclamação
- info: Cliente quer informações gerais (horário, entrega)
- outros: Não se encaixa acima
Responda APENAS com palavra-chave (preco/estoque/compra/suporte/info/outros)
'''
},
{'role': 'user', 'content': mensagem}
],
temperature=0.3,
max_tokens=10
)
intencao = response.choices[0].message.content.strip().lower()
return intencao
except Exception as e:
logger.error(f'Erro detectar intenção: {str(e)}')
return 'outros'
Passo 7: Lógica Atendimento (handlers.py)
import logging
from whatsapp import enviar_mensagem_texto, buscar_contato
from chatgpt import gerar_resposta, detectar_intencao
from database import (
salvar_mensagem,
buscar_historico,
criar_ou_atualizar_contato
)
logger = logging.getLogger(__name__)
def processar_mensagem(message_data):
"""
Processa mensagem recebida WhatsApp
"""
try:
# Extrair dados
numero = message_data.get('key', {}).get('remoteJid', '').replace('@s.whatsapp.net', '')
mensagem_texto = message_data.get('message', {}).get('conversation', '')
if not mensagem_texto:
# Tentar extrair de outros tipos mensagem
mensagem_texto = (
message_data.get('message', {}).get('extendedTextMessage', {}).get('text', '') or
message_data.get('message', {}).get('imageMessage', {}).get('caption', '')
)
if not numero or not mensagem_texto:
logger.warning('Mensagem sem número ou texto')
return
logger.info(f'Mensagem de {numero}: {mensagem_texto}')
# Buscar nome contato
nome = buscar_contato(numero)
# Salvar mensagem banco
salvar_mensagem(numero, mensagem_texto, 'inbound')
# Criar/atualizar contato
criar_ou_atualizar_contato(numero, nome)
# Detectar intenção
intencao = detectar_intencao(mensagem_texto)
logger.info(f'Intenção detectada: {intencao}')
# Roteamento por intenção
if intencao == 'preco':
resposta = handle_preco(mensagem_texto)
elif intencao == 'estoque':
resposta = handle_estoque(mensagem_texto)
elif intencao == 'compra':
resposta = handle_compra(numero, mensagem_texto)
elif intencao == 'suporte':
resposta = handle_suporte(numero, mensagem_texto)
else:
# ChatGPT genérico
historico = buscar_historico(numero, limit=5)
resposta = gerar_resposta(mensagem_texto, historico)
# Enviar resposta
enviar_mensagem_texto(numero, resposta)
# Salvar resposta banco
salvar_mensagem(numero, resposta, 'outbound')
except Exception as e:
logger.error(f'Erro processar mensagem: {str(e)}')
enviar_mensagem_texto(numero, 'Desculpe, tive um problema. Tente novamente em instantes! 😅')
def handle_preco(mensagem):
"""
Cliente perguntou preço produto
"""
# Aqui você consultaria banco dados/API produtos
# Exemplo simplificado:
if 'iphone' in mensagem.lower():
return '''iPhone 15 Pro 256GB: R$ 7.899
iPhone 15 128GB: R$ 5.999
Qual te interessa? 😊'''
return "Deixa eu consultar preço atualizado! Qual produto exato você quer? 😊"
def handle_estoque(mensagem):
"""
Cliente perguntou estoque
"""
return "Temos disponível em estoque! Entrega expressa 3-5 dias. Quer fechar pedido? 📦"
def handle_compra(numero, mensagem):
"""
Cliente quer comprar
"""
# Aqui você criaria pedido no sistema
# Integraria com Stripe/Mercado Pago
return f'''Ótimo! Vou gerar link pagamento.
Como prefere pagar?
💳 Cartão crédito
🔵 PIX (5% desconto)
📄 Boleto (vence 3 dias)
Responda número da opção!'''
def handle_suporte(numero, mensagem):
"""
Cliente tem problema
"""
# Criar ticket Zendesk
# Notificar atendente humano
return f'''Entendo sua situação 😔
Já chamei nosso time suporte.
Alguém responde em até 10 minutos.
Pode detalhar problema?'''
Passo 8: Banco Dados (database.py)
import psycopg2
from psycopg2.extras import RealDictCursor
import os
import logging
from datetime import datetime
logger = logging.getLogger(__name__)
DATABASE_URL = os.getenv('DATABASE_URL')
def get_connection():
"""Retorna conexão PostgreSQL"""
return psycopg2.connect(DATABASE_URL, cursor_factory=RealDictCursor)
def init_database():
"""
Cria tabelas se não existirem
"""
try:
conn = get_connection()
cursor = conn.cursor()
# Tabela contatos
cursor.execute('''
CREATE TABLE IF NOT EXISTS contatos (
id SERIAL PRIMARY KEY,
numero VARCHAR(20) UNIQUE NOT NULL,
nome VARCHAR(255),
primeiro_contato TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ultimo_contato TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# Tabela mensagens
cursor.execute('''
CREATE TABLE IF NOT EXISTS mensagens (
id SERIAL PRIMARY KEY,
numero VARCHAR(20) NOT NULL,
mensagem TEXT NOT NULL,
direcao VARCHAR(10) NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (numero) REFERENCES contatos(numero)
)
''')
conn.commit()
cursor.close()
conn.close()
logger.info('Banco dados inicializado')
except Exception as e:
logger.error(f'Erro init database: {str(e)}')
def criar_ou_atualizar_contato(numero, nome):
"""
Cria novo contato ou atualiza último contato
"""
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute('''
INSERT INTO contatos (numero, nome, ultimo_contato)
VALUES (%s, %s, CURRENT_TIMESTAMP)
ON CONFLICT (numero)
DO UPDATE SET ultimo_contato = CURRENT_TIMESTAMP, nome = EXCLUDED.nome
''', (numero, nome))
conn.commit()
cursor.close()
conn.close()
except Exception as e:
logger.error(f'Erro criar contato: {str(e)}')
def salvar_mensagem(numero, mensagem, direcao):
"""
Salva mensagem banco
Args:
direcao: 'inbound' ou 'outbound'
"""
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute('''
INSERT INTO mensagens (numero, mensagem, direcao)
VALUES (%s, %s, %s)
''', (numero, mensagem, direcao))
conn.commit()
cursor.close()
conn.close()
except Exception as e:
logger.error(f'Erro salvar mensagem: {str(e)}')
def buscar_historico(numero, limit=10):
"""
Busca histórico conversas (para contexto ChatGPT)
Returns:
list: [{'role': 'user', 'content': '...'}, ...]
"""
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute('''
SELECT mensagem, direcao
FROM mensagens
WHERE numero = %s
ORDER BY timestamp DESC
LIMIT %s
''', (numero, limit))
mensagens = cursor.fetchall()
cursor.close()
conn.close()
# Formatar para ChatGPT
historico = []
for msg in reversed(mensagens):
role = 'user' if msg['direcao'] == 'inbound' else 'assistant'
historico.append({'role': role, 'content': msg['mensagem']})
return historico
except Exception as e:
logger.error(f'Erro buscar histórico: {str(e)}')
return []
Passo 9: Deploy VPS (Ubuntu)
# SSH no servidor
ssh root@seu-servidor.com
# Instalar Python e dependências
apt update
apt install python3 python3-pip python3-venv postgresql nginx -y
# Clonar projeto (ou upload via SCP)
cd /root
git clone https://github.com/seu-usuario/whatsapp-bot.git
cd whatsapp-bot
# Criar virtual environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Configurar .env
nano .env
# [COLAR CONFIGURAÇÕES]
# Setup PostgreSQL
sudo -u postgres psql
CREATE DATABASE whatsapp_bot;
CREATE USER bot_user WITH PASSWORD 'senha123';
GRANT ALL PRIVILEGES ON DATABASE whatsapp_bot TO bot_user;
\q
# Testar aplicação
python app.py
# Acessar: http://IP:5000/health
# Setup Gunicorn (produção)
gunicorn --bind 0.0.0.0:5000 --workers 2 app:app
# PM2 (process manager)
npm install -g pm2
pm2 start "gunicorn --bind 0.0.0.0:5000 --workers 2 app:app" --name whatsapp-bot
pm2 save
pm2 startup
# Nginx reverse proxy
nano /etc/nginx/sites-available/whatsapp-bot
server {
listen 80;
server_name bot.seudominio.com;
location / {
proxy_pass http://localhost:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
ln -s /etc/nginx/sites-available/whatsapp-bot /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx
# SSL (Certbot)
apt install certbot python3-certbot-nginx -y
certbot --nginx -d bot.seudominio.com
Passo 10: Configurar Webhook Evolution API
curl -X POST 'https://evolution.seudominio.com/webhook/set/cliente-atendimento' \
-H 'Content-Type: application/json' \
-H 'apikey: SUA-CHAVE' \
-d '{
"url": "https://bot.seudominio.com/webhook/whatsapp",
"webhook_by_events": false,
"events": ["messages.upsert"]
}'
Testar: Enviar mensagem WhatsApp → Bot deve responder automaticamente ✅
Features Avançadas
1. Rate Limiting (Evitar Spam)
from functools import wraps
from time import time
# Cache último contato por número
ultimos_contatos = {}
def rate_limit(seconds=3):
"""
Impede múltiplas respostas em X segundos
"""
def decorator(func):
@wraps(func)
def wrapper(numero, *args, **kwargs):
agora = time()
ultimo = ultimos_contatos.get(numero, 0)
if agora - ultimo < seconds:
logger.warning(f'Rate limit {numero}')
return
ultimos_contatos[numero] = agora
return func(numero, *args, **kwargs)
return wrapper
return decorator
@rate_limit(seconds=5)
def processar_mensagem_safe(numero, mensagem):
# Lógica bot
pass
2. Typing Indicator
def enviar_com_typing(numero, texto, delay=2):
"""
Simula digitando antes de enviar
"""
import time
# Ativar "digitando..."
requests.post(
f'{EVOLUTION_URL}/chat/sendPresence/{INSTANCE}',
headers={'apikey': API_KEY},
json={'number': numero, 'presence': 'composing'}
)
time.sleep(delay)
# Enviar mensagem
enviar_mensagem_texto(numero, texto)
# Desativar "digitando"
requests.post(
f'{EVOLUTION_URL}/chat/sendPresence/{INSTANCE}',
headers={'apikey': API_KEY},
json={'number': numero, 'presence': 'available'}
)
3. Botões Interativos
def enviar_mensagem_botoes(numero, texto, botoes):
"""
Envia mensagem com botões clicáveis
Args:
botoes: [{'id': '1', 'text': 'Sim'}, {'id': '2', 'text': 'Não'}]
"""
url = f'{EVOLUTION_URL}/message/sendButtons/{INSTANCE}'
payload = {
'number': numero,
'buttonMessage': {
'text': texto,
'buttons': [
{'buttonId': b['id'], 'buttonText': {'displayText': b['text']}}
for b in botoes
]
}
}
requests.post(url, json=payload, headers={'apikey': API_KEY})
# Uso
enviar_mensagem_botoes(
'5511999887766',
'Quer continuar atendimento?',
[
{'id': 'sim', 'text': '✅ Sim'},
{'id': 'nao', 'text': '❌ Não'}
]
)
Casos Reais ROI
Caso 1: E-commerce - Bot qualificação leads (ROI 800%)
Código bot:
def qualificar_lead(numero, mensagem):
"""
Qualifica lead e-commerce
"""
# ChatGPT analisa mensagem
score = calcular_score_ia(mensagem)
if score >= 70:
# Lead quente → Notificar vendedor
enviar_alerta_vendedor(numero)
return "Ótimo! Já chamei vendedor. Responde em 2 min! 😊"
else:
# Lead frio → Nutrir
return "Legal! Enviei catálogo por email. Dúvidas? Responda aqui! 📧"
Resultado:
- 500 leads/mês qualificados automaticamente
- Vendedores focam só quentes (score 70+)
- Conversão: 6% → 18% (+200%)
- ROI: R$ 120k vendas extras vs R$ 15k custo
Caso 2: Clínica - Agendamento automático (95% automação)
Bot agendamento:
def agendar_consulta(numero, data_hora, especialidade):
"""
Integra Google Calendar API
"""
# Criar evento
evento = calendar.events().insert(
calendarId='clinica@gmail.com',
body={
'summary': f'Consulta {especialidade}',
'start': {'dateTime': data_hora},
'end': {'dateTime': calcular_fim(data_hora, 30)}, # 30 min
'attendees': [{'email': buscar_email(numero)}]
}
).execute()
# Confirmar WhatsApp
enviar_mensagem_texto(numero, f'''
✅ Agendado!
📅 {formatar_data(data_hora)}
👨⚕️ {especialidade}
📍 Rua X, 123
Lembrete: Envio 24h antes!
''')
Resultado: 95% agendamentos automáticos (atendente só confirma casos especiais)
Próximos passos
- Evolution API Tutorial - Setup API completo
- Chatbot WhatsApp IA - IA conversacional
- N8N WhatsApp - Alternativa no-code
- Flask Python Tutorial - Fundamentos Flask
- Docker Tutorial - Containerizar bot
- API OpenAI Python - Integração ChatGPT
- Automação Python - Automações avançadas
Precisa desenvolver bot WhatsApp Python customizado? A Agência Café Online já criou 40+ bots (ROI médio 600%). Consultoria grátis.
Sobre o autor: Felipe Zanoni desenvolve bots WhatsApp Python há 4 anos, com 2M+ mensagens processadas/mês e 99.9% uptime em produção.