Skip to content

Recebendo Mensagens

Aprenda como receber e processar mensagens através de webhooks.

Como Funciona

Quando alguém envia uma mensagem para seu número conectado:

  1. WhatsApp envia para o ZapFlare
  2. ZapFlare processa e valida
  3. ZapFlare envia para seu webhook
  4. Você processa e responde (opcional)

Configurando Webhook

Durante Criação da Instância

javascript
const instance = await createInstance({
  name: "Atendimento",
  webhookUrl: "https://meu-site.com/webhook/whatsapp"
});

Atualizando Webhook Existente

bash
PUT /whatsapp/instances/{instanceId}
Content-Type: application/json

{
  "webhookUrl": "https://novo-webhook.com/whatsapp"
}

Estrutura do Webhook

Mensagem de Texto

json
{
  "event": "messages.upsert",
  "instance": {
    "instanceName": "Atendimento",
    "instanceId": "inst_abc123"
  },
  "data": {
    "key": {
      "remoteJid": "5511999999999@s.whatsapp.net",
      "fromMe": false,
      "id": "BAE5C8F9A2B4E231"
    },
    "message": {
      "conversation": "Olá, preciso de ajuda!",
      "messageTimestamp": "1704456789"
    },
    "messageType": "conversation",
    "pushName": "João Silva",
    "phone": "5511999999999"
  }
}

Mensagem com Mídia

json
{
  "event": "messages.upsert",
  "instance": {
    "instanceName": "Atendimento",
    "instanceId": "inst_abc123"
  },
  "data": {
    "key": {
      "remoteJid": "5511999999999@s.whatsapp.net",
      "fromMe": false,
      "id": "BAE5C8F9A2B4E232"
    },
    "message": {
      "imageMessage": {
        "url": "https://mmg.whatsapp.net/...",
        "mimetype": "image/jpeg",
        "caption": "Veja esta imagem",
        "fileLength": "43234",
        "mediaKey": "..."
      }
    },
    "messageType": "imageMessage",
    "pushName": "João Silva",
    "phone": "5511999999999"
  }
}

Implementando o Webhook

Node.js com Express

javascript
const express = require('express');
const crypto = require('crypto');
const app = express();

// Middleware para receber o body raw
app.use(express.raw({ type: 'application/json' }));

// Validar assinatura HMAC
function validateSignature(body, signature, secret) {
  const hash = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  
  return `sha256=${hash}` === signature;
}

// Endpoint do webhook
app.post('/webhook/whatsapp', async (req, res) => {
  // Validar assinatura
  const signature = req.headers['x-hub-signature-256'];
  const secret = process.env.WEBHOOK_SECRET;
  
  if (!validateSignature(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Parse do evento
  const event = JSON.parse(req.body);
  
  // Processar diferentes tipos de eventos
  switch (event.event) {
    case 'messages.upsert':
      await handleNewMessage(event.data);
      break;
      
    case 'messages.update':
      await handleMessageUpdate(event.data);
      break;
      
    case 'connection.update':
      await handleConnectionUpdate(event.data);
      break;
  }
  
  // Sempre retornar 200 rapidamente
  res.status(200).send('OK');
});

async function handleNewMessage(data) {
  // Ignorar mensagens enviadas por nós
  if (data.key.fromMe) return;
  
  const from = data.phone;
  const message = data.message.conversation || 
                 data.message.extendedTextMessage?.text || 
                 '';
  
  console.log(`Nova mensagem de ${from}: ${message}`);
  
  // Responder automaticamente
  if (message.toLowerCase().includes('ajuda')) {
    await sendMessage(from, 'Olá! Como posso ajudar você?');
  }
}

app.listen(3000, () => {
  console.log('Webhook rodando na porta 3000');
});

Python com Flask

python
from flask import Flask, request, abort
import hmac
import hashlib
import json

app = Flask(__name__)

def validate_signature(body, signature, secret):
    expected = hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    
    return f'sha256={expected}' == signature

@app.route('/webhook/whatsapp', methods=['POST'])
def webhook():
    # Validar assinatura
    signature = request.headers.get('X-Hub-Signature-256')
    secret = 'seu_webhook_secret'
    
    if not validate_signature(request.data, signature, secret):
        abort(401)
    
    # Processar evento
    event = request.json
    
    if event['event'] == 'messages.upsert':
        handle_new_message(event['data'])
    
    return 'OK', 200

def handle_new_message(data):
    if data['key']['fromMe']:
        return
    
    phone = data['phone']
    message = data['message'].get('conversation', '')
    
    print(f'Nova mensagem de {phone}: {message}')

if __name__ == '__main__':
    app.run(port=3000)

Tipos de Eventos

messages.upsert

Nova mensagem recebida ou enviada

messages.update

Atualização de status (entregue, lido)

connection.update

Mudança no status da conexão

groups.update

Eventos de grupos (adição, remoção)

presence.update

Status online/digitando

Processamento Assíncrono

Para não bloquear o webhook:

javascript
const Queue = require('bull');
const messageQueue = new Queue('messages');

// No webhook
app.post('/webhook/whatsapp', async (req, res) => {
  const event = JSON.parse(req.body);
  
  // Adicionar à fila
  await messageQueue.add('process', event);
  
  // Responder imediatamente
  res.send('OK');
});

// Processador
messageQueue.process('process', async (job) => {
  const event = job.data;
  
  // Processamento demorado aqui
  await processEvent(event);
});

Boas Práticas

  1. Responda Rápido - Retorne 200 em menos de 5 segundos
  2. Valide Assinaturas - Sempre verifique a autenticidade
  3. Idempotência - Trate mensagens duplicadas
  4. Logs - Registre todos os eventos
  5. Retry - Implemente reprocessamento para falhas

Testando Webhooks

Desenvolvimento Local

Use ngrok para expor seu servidor local:

bash
ngrok http 3000

Configure o webhook com a URL do ngrok:

https://abc123.ngrok.io/webhook/whatsapp

Teste Manual

bash
POST /whatsapp/instances/{instanceId}/webhook/test

Próximos Passos

Desenvolvido com ❤️ pela equipe ZapFlare