# Guia Evolution e Baileys

## Quando usar este guia

Use este documento quando a sua integracao recebe eventos de mensagem por:

- `Evolution API`
- `Baileys`
- qualquer bridge Node.js parecida

Aqui a regra continua a mesma:

1. receber o evento
2. transformar em um body simples
3. chamar o ChatAgent
4. devolver `reply`

## Regra mais importante

Se o seu codigo escolhe o numero certo pela credencial, use a **API key do numero**.

Se o seu codigo ainda usa a **API key geral do tenant**, mande `number_id` junto no body.

## Evolution API

### Fluxo recomendado

1. receber o evento da Evolution
2. extrair `from`, `name` e `message`
3. chamar o ChatAgent
4. usar `reply` no envio final da Evolution

### Body esperado

#### Com API key do numero

```json
{
  "from": "jid-ou-numero-do-contato",
  "name": "nome-do-contato",
  "message": "texto-da-mensagem"
}
```

#### Com API key geral do tenant

```json
{
  "number_id": 12,
  "from": "jid-ou-numero-do-contato",
  "name": "nome-do-contato",
  "message": "texto-da-mensagem"
}
```

### Erros comuns

- usar um identificador instavel em `from`
- mandar um objeto inteiro em `message`
- esquecer `number_id` quando a chave usada e a do tenant
- tentar responder com o campo errado em vez de `reply`

## Baileys

### Exemplo funcional com API key do numero

```js
sock.ev.on('messages.upsert', async ({ messages }) => {
  const msg = messages[0];
  const text = msg.message?.conversation || msg.message?.extendedTextMessage?.text;
  if (!text || msg.key.fromMe) return;

  const res = await fetch('https://seu-dominio/api/whatsapp/message', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer SUA_API_KEY_DO_NUMERO',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      from: msg.key.remoteJid,
      name: msg.pushName,
      message: text
    })
  });

  const data = await res.json();
  await sock.sendMessage(msg.key.remoteJid, { text: data.reply });
});
```

### Exemplo com API key geral do tenant

```js
sock.ev.on('messages.upsert', async ({ messages }) => {
  const msg = messages[0];
  const text = msg.message?.conversation || msg.message?.extendedTextMessage?.text;
  if (!text || msg.key.fromMe) return;

  const res = await fetch('https://seu-dominio/api/whatsapp/message', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer SUA_API_KEY_GERAL',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      number_id: 12,
      from: msg.key.remoteJid,
      name: msg.pushName,
      message: text
    })
  });

  const data = await res.json();
  await sock.sendMessage(msg.key.remoteJid, { text: data.reply });
});
```

## O que esses exemplos fazem certo

- `msg.key.remoteJid` vira `from`
- `msg.pushName` vira `name`
- o texto vira `message`
- `data.reply` volta para o contato
- mensagens `fromMe` sao ignoradas

## O que voce ainda deve acrescentar em producao

- timeout
- tratamento de erro HTTP
- log com `thread_id`
- retry controlado
- monitoramento

## Casos em que costuma dar erro

### Loop de resposta

Normalmente acontece quando voce esquece:

```js
if (!text || msg.key.fromMe) return;
```

### Conversa sem memoria

Normalmente acontece quando:

- o `from` nao usa `msg.key.remoteJid`
- ou usa outro valor que muda entre eventos

### Erro `400`

Normalmente acontece quando:

- `message` recebeu um objeto em vez do texto
- faltou `number_id` com a chave do tenant

## Validacao

Antes de subir:

- teste com conversa real
- confirme que `msg.key.remoteJid` chega igual para o mesmo contato
- confirme que a resposta enviada ao cliente vem de `data.reply`
- confirme que mensagens `fromMe` nao entram em loop
- confira que o `thread_id` volta no formato `number:<id>:whatsapp:<from>`
