Pular para o conteúdo principal

WhatsApp Business API + n8n

Integração completa do WhatsApp Business API via n8n para campanhas de CRM, confirmações e bot de atendimento.

Arquitetura da Integração

sequenceDiagram
participant Admin as Painel Admin
participant API as Lambda API
participant SQS as SQS Queue
participant Worker as Messaging Worker
participant N8N as n8n
participant Meta as WhatsApp Business API
participant Client as Cliente Final

Admin->>API: Criar campanha CRM
API->>SQS: Publicar mensagens em lote
Worker->>SQS: Consumir batch (10 mensagens)

loop Para cada destinatário
Worker->>N8N: POST /webhook/send-whatsapp
N8N->>Meta: Enviar template message
Meta->>Client: Entregar WhatsApp
Meta-->>N8N: Webhook status (delivered/read/failed)
N8N-->>API: Atualizar status via callback
end

Configuração do WhatsApp Business API

1. Pré-requisitos Meta

  • Meta Business Account ativo
  • WhatsApp Business Account verificado
  • Número de telefone verificado e aprovado
  • App criado no Meta Developers Console

2. Configuração no Meta Business Manager

# 1. Criar app no Meta Developers
# 2. Adicionar produto "WhatsApp"
# 3. Configurar webhook endpoint
WEBHOOK_URL=https://bitio-api.com/webhooks/whatsapp
VERIFY_TOKEN=seu-token-verificacao-seguro

# 4. Adicionar número de telefone
PHONE_NUMBER_ID=123456789

3. Tokens e Credenciais

# Variáveis de ambiente necessárias
META_APP_ID=sua-app-id
META_APP_SECRET=seu-app-secret
WHATSAPP_TOKEN=seu-whatsapp-token-permanente
WHATSAPP_PHONE_ID=seu-phone-number-id
WHATSAPP_WEBHOOK_VERIFY_TOKEN=token-verificacao

Setup do n8n

1. Instalação via Docker

# docker-compose.yml
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
container_name: bitio-n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_HOST=n8n.bitio.internal
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.bitio.com
- NODE_ENV=production
volumes:
- n8n_data:/home/node/.n8n
networks:
- bitio-network

volumes:
n8n_data:

networks:
bitio-network:
external: true

2. Configuração de Credenciais

No painel do n8n, configurar:

// WhatsApp Business Credentials
{
"name": "WhatsApp Business - Bitio",
"type": "httpHeaderAuth",
"data": {
"headerAuth": {
"name": "Authorization",
"value": "Bearer {{WHATSAPP_TOKEN}}"
}
}
}

Workflows n8n

1. Workflow: Enviar Campanha WhatsApp

{
"name": "Send WhatsApp Campaign",
"nodes": [
{
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"parameters": {
"httpMethod": "POST",
"path": "send-whatsapp",
"responseMode": "responseNode"
}
},
{
"name": "Validate Input",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Validar payload\nconst { phone, template, variables, metadata } = $input.first().json;\n\nif (!phone || !template) {\n throw new Error('Phone and template are required');\n}\n\nreturn [{\n json: {\n phone: phone.replace(/\\D/g, ''), // Limpar formatação\n template,\n variables: variables || {},\n metadata: metadata || {}\n }\n}];"
}
},
{
"name": "Send to WhatsApp API",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://graph.facebook.com/v18.0/{{WHATSAPP_PHONE_ID}}/messages",
"method": "POST",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{WHATSAPP_TOKEN}}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "messaging_product",
"value": "whatsapp"
},
{
"name": "to",
"value": "={{ $json.phone }}"
},
{
"name": "type",
"value": "template"
},
{
"name": "template",
"value": "={{ JSON.stringify({\n name: $json.template,\n language: { code: 'pt_BR' },\n components: [\n {\n type: 'body',\n parameters: Object.keys($json.variables).map(key => ({\n type: 'text',\n text: $json.variables[key]\n }))\n }\n ]\n}) }}"
}
]
}
}
},
{
"name": "Update Campaign Status",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.bitio.com/v1/campaigns/update-status",
"method": "POST",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{BITIO_API_TOKEN}}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "messageId",
"value": "={{ $json.messages[0].id }}"
},
{
"name": "status",
"value": "sent"
},
{
"name": "metadata",
"value": "={{ JSON.stringify($('Webhook Trigger').first().json.metadata) }}"
}
]
}
}
},
{
"name": "Response",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": {
"responseCode": 200,
"responseBody": "={{ JSON.stringify({ success: true, messageId: $json.messages[0].id }) }}"
}
}
]
}

2. Workflow: Processar Webhooks de Status

{
"name": "WhatsApp Status Webhook",
"nodes": [
{
"name": "Webhook Listener",
"type": "n8n-nodes-base.webhook",
"parameters": {
"httpMethod": "POST",
"path": "whatsapp-status",
"responseCode": 200
}
},
{
"name": "Process Status Update",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Processar webhook da Meta\nconst data = $input.first().json;\n\n// Verificar se é status de mensagem\nif (data.entry?.[0]?.changes?.[0]?.value?.statuses) {\n const statuses = data.entry[0].changes[0].value.statuses;\n \n return statuses.map(status => ({\n json: {\n messageId: status.id,\n recipientId: status.recipient_id,\n status: status.status, // sent, delivered, read, failed\n timestamp: status.timestamp,\n error: status.errors?.[0]\n }\n }));\n}\n\nreturn [];"
}
},
{
"name": "Update Database",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.bitio.com/v1/whatsapp/update-status",
"method": "POST",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "messageId",
"value": "={{ $json.messageId }}"
},
{
"name": "status",
"value": "={{ $json.status }}"
},
{
"name": "timestamp",
"value": "={{ $json.timestamp }}"
}
]
}
}
}
]
}

Templates Aprovados

1. Template de Campanha CRM

{
"name": "campanha_crm",
"category": "MARKETING",
"language": "pt_BR",
"components": [
{
"type": "BODY",
"text": "Olá {{1}}! 🍽️\n\nTemos uma oferta especial para você: {{2}}\n\nClique aqui para ver: {{3}}\n\nVálido até amanhã!"
},
{
"type": "FOOTER",
"text": "Para parar de receber mensagens, responda PARE"
}
]
}

2. Template de Confirmação de Reserva

{
"name": "confirmacao_reserva",
"category": "UTILITY",
"language": "pt_BR",
"components": [
{
"type": "BODY",
"text": "✅ Reserva confirmada!\n\n👤 Nome: {{1}}\n📅 Data: {{2}}\n⏰ Horário: {{3}}\n🏪 Local: {{4}}\n\nNos vemos lá!"
}
]
}

3. Template de Cupom Fidelidade

{
"name": "cupom_fidelidade",
"category": "UTILITY",
"language": "pt_BR",
"components": [
{
"type": "BODY",
"text": "🎉 Parabéns {{1}}!\n\nVocê desbloqueou: {{2}}\n\nSeu cupom: *{{3}}*\n\nApresente este código no balcão para resgatar!"
}
]
}

Integração com o Backend

1. Messaging Worker (Node.js)

// messaging-worker.ts
import { SQSClient, ReceiveMessageCommand, DeleteMessageCommand } from '@aws-sdk/client-sqs';

interface WhatsAppMessage {
customerId: string;
phone: string;
template: string;
variables: Record<string, string>;
campaignId?: string;
}

export class MessagingWorker {
private sqs = new SQSClient({ region: 'sa-east-1' });
private queueUrl = process.env.WHATSAPP_QUEUE_URL!;
private n8nWebhook = process.env.N8N_WEBHOOK_URL!;

async processMessages() {
try {
const command = new ReceiveMessageCommand({
QueueUrl: this.queueUrl,
MaxNumberOfMessages: 10,
WaitTimeSeconds: 20, // Long polling
});

const result = await this.sqs.send(command);

if (result.Messages) {
await Promise.all(
result.Messages.map(msg => this.processMessage(msg))
);
}
} catch (error) {
logger.error('Error processing messages', { error });
}
}

private async processMessage(sqsMessage: any) {
try {
const message: WhatsAppMessage = JSON.parse(sqsMessage.Body);

// Chamar n8n webhook
const response = await fetch(this.n8nWebhook, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
phone: message.phone,
template: message.template,
variables: message.variables,
metadata: {
customerId: message.customerId,
campaignId: message.campaignId,
},
}),
});

if (response.ok) {
// Remover mensagem da fila se sucesso
await this.sqs.send(new DeleteMessageCommand({
QueueUrl: this.queueUrl,
ReceiptHandle: sqsMessage.ReceiptHandle,
}));

logger.info('Message sent successfully', {
customerId: message.customerId,
phone: message.phone,
});
} else {
throw new Error(`n8n webhook failed: ${response.status}`);
}
} catch (error) {
logger.error('Failed to process message', {
error,
message: sqsMessage.Body,
});
// Mensagem volta para fila (retry automático)
}
}
}

// Iniciar worker
const worker = new MessagingWorker();
setInterval(() => worker.processMessages(), 5000);

2. Webhook Handler (Lambda)

// webhook-handler.ts
import { APIGatewayProxyHandler } from 'aws-lambda';

export const whatsappWebhook: APIGatewayProxyHandler = async (event) => {
try {
// Verificar token de verificação (setup inicial)
if (event.queryStringParameters?.['hub.mode'] === 'subscribe') {
const token = event.queryStringParameters['hub.verify_token'];
if (token === process.env.WHATSAPP_VERIFY_TOKEN) {
return {
statusCode: 200,
body: event.queryStringParameters['hub.challenge'] || '',
};
}
}

// Processar webhook de status
const body = JSON.parse(event.body || '{}');

if (body.entry?.[0]?.changes?.[0]?.value?.statuses) {
await processStatusUpdates(body.entry[0].changes[0].value.statuses);
}

// Processar mensagens recebidas (inbound)
if (body.entry?.[0]?.changes?.[0]?.value?.messages) {
await processInboundMessages(body.entry[0].changes[0].value.messages);
}

return { statusCode: 200, body: 'OK' };
} catch (error) {
logger.error('Webhook error', { error });
return { statusCode: 500, body: 'Error' };
}
};

async function processStatusUpdates(statuses: any[]) {
for (const status of statuses) {
await prisma.campaignRecipient.updateMany({
where: { messageId: status.id },
data: {
status: status.status,
[`${status.status}At`]: new Date(parseInt(status.timestamp) * 1000),
},
});
}
}

Rate Limiting e Otimização

1. Limites da API WhatsApp

  • 1000 mensagens por segundo por número de telefone
  • Janela de conversa de 24h (cobrança por conversa, não por mensagem)
  • Templates pré-aprovados obrigatórios para mensagens de marketing

2. Otimização no n8n

// Rate limiting no workflow
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

// Entre cada envio
await delay(100); // 10 msgs/segundo (dentro do limite)

// Retry em caso de erro 429 (rate limit)
if (response.status === 429) {
const retryAfter = response.headers['retry-after'] || 60;
await delay(retryAfter * 1000);
// Retry da mensagem
}

Monitoramento e Alertas

1. Métricas Principais

  • Taxa de entrega (delivered/sent)
  • Taxa de leitura (read/delivered)
  • Taxa de falha (failed/sent)
  • Latência média de processamento
  • Volume por hora/dia

2. Alertas Críticos

  • Token expirado ou inválido
  • Webhook fora do ar por >5 minutos
  • Fila SQS acumulando >1000 mensagens
  • Taxa de falha >5% em 1 hora
  • n8n workflow com erro repetido

3. Dashboard Grafana

-- Métricas de campanha (últimas 24h)
SELECT
status,
COUNT(*) as count,
(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER()) as percentage
FROM campaign_recipients
WHERE created_at >= NOW() - INTERVAL '24 hours'
GROUP BY status;

Troubleshooting

Problemas Comuns

ErroCausaSolução
Token inválidoToken expirado/revogadoRenovar token no Meta Business
Template não encontradoNome incorreto/não aprovadoVerificar templates aprovados
Número inválidoFormato incorretoValidar formato +5511999999999
Rate limitMuitas mensagens/segundoImplementar backoff no n8n
Webhook não recebidoURL/token incorretoVerificar configuração Meta

Logs para Investigação

# Logs do n8n
docker logs bitio-n8n --tail 100 -f

# Logs do worker
journalctl -u bitio-worker -f

# Logs da Lambda (CloudWatch)
aws logs tail /aws/lambda/bitio-whatsapp-webhook --follow

Esta integração permite campanhas WhatsApp escaláveis e confiáveis, com rastreamento completo de entrega e resposta automática a interações dos clientes.