> ## Documentation Index
> Fetch the complete documentation index at: https://developer.wabox.me/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Wabox é uma API não-oficial de WhatsApp (aparelho vinculado). Tudo é snake_case; a base é https://api.wabox.me/instances/{instance_id}/token/{token}.
> Envios respondem { id, message_id, wabox_id, status: "queued" } na hora; o resultado real chega no webhook delivery. Envios não são idempotentes: confira GET /queue antes de repetir.
> Sempre verifique X-Wabox-Signature (HMAC-SHA256 de "<t>.<corpo cru>") nos webhooks e deduplique por event_id.
> Botões, listas, carrossel e catálogo são best effort e não renderizam no WhatsApp Web/Desktop. Não existem: chamadas, listas de transmissão, histórico de mensagens, instância mobile.
> Não invente endpoints ou campos: use o OpenAPI em https://api.wabox.me/openapi.json.

# n8n

> Receba mensagens do WhatsApp em um workflow do n8n e responda com o nó de requisição HTTP.

Você vai montar um workflow com três partes: um nó **Webhook** que recebe o evento `received` do Wabox, um filtro que ignora o que não interessa e um nó **HTTP Request** que responde pelo `send-text`. A verificação de assinatura e a deduplicação por `event_id` ficam no final, como etapas opcionais.

<Note>
  Os exemplos usam `https://api.wabox.me/instances/{instance_id}/token/{token}` como base. Troque `{instance_id}` e `{token}` pelos valores da instância (dashboard › instância › Credenciais). Envie o header `Client-Token` só se ele estiver ativado no seu workspace — veja [Client-Token](/security/client-token).
</Note>

## Receber mensagens

<Steps>
  <Step title="Crie o nó Webhook">
    Adicione um nó **Webhook** ao workflow e configure:

    * **HTTP Method**: `POST`
    * **Path**: um caminho seu, por exemplo `wabox-received`
    * **Respond**: *Immediately* — o n8n devolve `200` antes de executar o resto do workflow. O Wabox espera a resposta em até 10 s e reenvia se não receber `2xx`; responder na hora evita reentregas duplicadas quando o workflow demora.

    O nó mostra duas URLs: a de **teste** (só escuta enquanto você clica em "Listen for test event") e a de **produção** (ativa quando o workflow está ligado). Use a de teste para montar, e troque pela de produção no Wabox antes de publicar.
  </Step>

  <Step title="Aponte o webhook received para o n8n">
    No dashboard, abra a instância e cole a URL no campo do webhook de mensagens recebidas. Ou faça pela API:

    ```bash theme={"system"}
    curl -X PUT "https://api.wabox.me/instances/{instance_id}/token/{token}/webhooks" \
      -H "Content-Type: application/json" \
      -d '{ "received_url": "https://SEU-N8N/webhook/wabox-received" }'
    ```

    A instância precisa estar conectada (QR lido) para receber mensagens — veja [Primeiros passos](/quickstart).
  </Step>

  <Step title="Mande uma mensagem de teste e inspecione o item">
    Clique em "Listen for test event", envie uma mensagem de texto para o número conectado e olhe a saída do nó. O n8n coloca o payload em `body` e os headers em `headers`. Os campos que você vai usar:

    | Expressão                       | O que é                                                  |
    | ------------------------------- | -------------------------------------------------------- |
    | `{{ $json.body.type }}`         | Tipo do evento (`received`)                              |
    | `{{ $json.body.phone }}`        | Número de quem mandou, só dígitos                        |
    | `{{ $json.body.text.message }}` | Texto da mensagem (só existe em mensagens de texto)      |
    | `{{ $json.body.from_me }}`      | `true` se foi enviada pelo próprio número                |
    | `{{ $json.body.is_group }}`     | `true` se veio de um grupo                               |
    | `{{ $json.body.message_id }}`   | Id da mensagem, para responder com `reply_to_message_id` |
    | `{{ $json.body.event_id }}`     | Id único da entrega, para deduplicar                     |

    O payload completo está em [Webhook received](/webhooks/received).
  </Step>

  <Step title="Filtre o que não deve gerar resposta">
    Adicione um nó **IF** entre o Webhook e a resposta com estas condições (todas verdadeiras):

    * `{{ $json.body.type }}` é igual a `received`
    * `{{ $json.body.from_me }}` é falso
    * `{{ $json.body.text }}` existe (imagens, áudios e documentos vêm sem `text`)

    <Warning>
      Se `notify_sent_by_me` estiver ligado nos filtros da instância, as mensagens que o próprio workflow envia voltam como `received` com `from_me: true`. Sem a condição de `from_me`, o workflow responde às próprias respostas em loop.
    </Warning>
  </Step>
</Steps>

## Responder pelo WhatsApp

<Steps>
  <Step title="Adicione o nó HTTP Request">
    Conecte um nó **HTTP Request** à saída "true" do IF:

    * **Method**: `POST`
    * **URL**: `https://api.wabox.me/instances/{instance_id}/token/{token}/send-text`
    * **Send Body**: ligado, **Body Content Type**: `JSON`, **Specify Body**: *Using JSON*
    * Corpo (com expressão ativada):

    ```json theme={"system"}
    {
      "phone": "{{ $json.body.phone }}",
      "message": "Recebemos sua mensagem: {{ $json.body.text.message }}"
    }
    ```

    Para responder citando a mensagem original, inclua `"reply_to_message_id": "{{ $json.body.message_id }}"`. Todos os campos aceitos estão em [POST /send-text](/api-reference/introduction).

    Se o `Client-Token` estiver ativado, adicione o header `Client-Token` na seção de headers do nó.
  </Step>

  <Step title="Leia a resposta">
    O envio é enfileirado e a API responde na hora:

    ```json theme={"system"}
    { "id": "3EB0A9C6D2F1E4B5A7D0", "message_id": "3EB0A9C6D2F1E4B5A7D0", "wabox_id": "wbx_01J5Q8ZK3M4N5P6Q7R8S9T0M01", "status": "queued" }
    ```

    `status: "queued"` não significa entregue. O resultado chega no webhook [delivery](/webhooks/delivery), com o mesmo `message_id`. Se quiser tratar falhas de envio no n8n, aponte `delivery_url` para outro nó Webhook (ou para o mesmo, separando pelo `body.type`).
  </Step>
</Steps>

<Tip>
  O token da instância faz parte da URL. Se o workflow for compartilhado ou exportado, ele vai junto. Guarde a URL base em uma variável do n8n em vez de digitá-la em cada nó, e rotacione o token se ele vazar — veja [Rotação de credenciais](/security/credential-rotation).
</Tip>

## Verificar a assinatura (opcional)

Toda entrega traz o header `X-Wabox-Signature: t=<unix>,v1=<hex>`, onde `v1` é o HMAC-SHA256 do texto `t + "." + corpo cru`, usando o `secret` da instância (`whsec_…`, visível em `GET /webhooks` e no painel). Detalhes em [Assinatura de webhooks](/security/webhook-signature).

<Warning>
  Por padrão o n8n entrega o corpo já interpretado como JSON, e a assinatura é calculada sobre os **bytes originais**. Re-serializar o objeto não reproduz o corpo cru (ordem de chaves, espaços, unicode). Ative a opção **Raw Body** nas opções do nó Webhook: o corpo original passa a chegar como dado binário no item, além do JSON em `body`.
</Warning>

Com Raw Body ligado, adicione um nó **Code** (modo "Run Once for Each Item") logo depois do Webhook:

```javascript theme={"system"}
const crypto = require('crypto');

const secret = 'whsec_SEU_SEGREDO'; // melhor: variável de ambiente do n8n
const header = $input.item.json.headers['x-wabox-signature'] ?? '';
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));

// Corpo cru: o n8n o entrega como binário quando "Raw Body" está ligado.
// Dependendo de como sua instalação armazena binários, pode ser necessário
// obter o buffer via this.helpers.getBinaryDataBuffer(0, 'data') em vez do base64 inline.
const raw = Buffer.from($input.item.binary.data.data, 'base64');

const expected = crypto
  .createHmac('sha256', secret)
  .update(`${parts.t}.${raw.toString('utf8')}`)
  .digest('hex');

const valid =
  expected.length === (parts.v1 ?? '').length &&
  crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(parts.v1, 'hex'));

const ageSec = Math.abs(Date.now() / 1000 - Number(parts.t));
if (!valid || ageSec > 300) {
  throw new Error('Assinatura de webhook inválida');
}

return $input.item;
```

Em instalações próprias, se o `require('crypto')` for bloqueado, libere o módulo com a variável de ambiente `NODE_FUNCTION_ALLOW_BUILTIN=crypto`.

## Deduplicar por `event_id`

Se o n8n demorar ou responder erro, o Wabox reenvia a mesma entrega (10 s, 1 min, 10 min, 1 h, 6 h) com o **mesmo** `event_id` — também disponível no header `X-Wabox-Event-Id`. Com "Respond immediately" isso é raro, mas um workflow idempotente não responde duas vezes ao cliente:

* Use o nó de remoção de duplicados do n8n configurado para lembrar valores entre execuções, com a chave `{{ $json.body.event_id }}`; ou
* Guarde os `event_id` já processados em um banco/Redis seu e descarte repetidos com um nó IF.

Mais sobre entregas e reenvios em [Visão geral dos webhooks](/webhooks/overview).
