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

# Webhooks

> Inscreva sistemas externos em eventos de WhatsApp, iMessage e SMS de entrada/saída, e eventos do sistema.

Os webhooks permitem enviar eventos em tempo real para qualquer endpoint externo. Use-os para sincronizar mensagens com seu CRM, acionar automações no n8n/Make/Zapier ou construir backends personalizados.

## Criar uma Assinatura de Webhook

<Steps>
  <Step title="Abra sua Location">
    Vá para **Dashboard → Locations** e selecione a location que você deseja inscrever.
  </Step>

  <Step title="Abra as Configurações">
    Clique na aba **Settings** (Configurações) dessa location.
  </Step>

  <Step title="Criar assinatura">
    Role até a seção **Webhooks** e clique em **Create subscription** (Criar assinatura).
  </Step>

  <Step title="Preencha o formulário">
    Complete o diálogo **Create subscription** (veja os campos abaixo).
  </Step>

  <Step title="Salvar">
    Clique em **Create subscription** para salvar. Se "Enviar um ping de teste" estiver ativado, um evento fictício será enviado via POST ao seu endpoint para verificar se ele funciona.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/goghl-whitelable/d0UJrCwlyc8wzaxE/images/features/assets/images/webhook.png?fit=max&auto=format&n=d0UJrCwlyc8wzaxE&q=85&s=3a5728c9bc59a7bda48b0e6f663725f1" alt="Criar assinatura de webhook" width="2886" height="1862" data-path="images/features/assets/images/webhook.png" />
</Frame>

## Campos da Assinatura

### Nome *(obrigatório)*

Um rótulo legível para que você possa identificar a assinatura depois (ex.: `Sincronização CRM`, `Handler de Entrada n8n`).

### URL de Destino

O endpoint HTTPS que receberá os payloads dos eventos.

```text theme={null}
https://example.com/webhooks
```

<Note>
  Seu endpoint deve responder com um código de status `2xx`. Respostas que não sejam 2xx são tratadas como falhas.
</Note>

### Selecionar eventos

Escolha exatamente quais eventos devem acionar um webhook. Você pode combinar canais em uma única assinatura.

#### WhatsApp

* **Inbound (Entrada)** - uma mensagem de WhatsApp é recebida
* **Outbound (Saída)** - uma mensagem de WhatsApp é enviada

#### iMessage

* **Inbound (Entrada)** - um iMessage é recebido
* **Outbound (Saída)** - um iMessage é enviado

#### SMS

* **Inbound (Entrada)** - um SMS é recebido
* **Outbound (Saída)** - um SMS é enviado

#### Sistema

* **Message failed (Falha na mensagem)** - uma mensagem não pôde ser entregue (use para lógica de novas tentativas ou alertas)

### Enviar um ping de teste após a criação

Quando ativado, o sistema enviará via POST um evento fictício para sua **URL de Destino** imediatamente após a criação da assinatura. Use isso para confirmar que seu endpoint está acessível e que seu handler interpreta os payloads corretamente.

<Tip>
  Deixe esta opção **ativada** na primeira assinatura que você criar para um novo endpoint.
</Tip>

<Note>
  O corpo do ping de teste é `{ "type": "test.ping" }`. Ele não está envolvido no envelope descrito abaixo.
</Note>

## Formato de Entrega

Todo evento, exceto o ping de teste, é enviado via POST como JSON, envolvido neste envelope:

```json theme={null}
{
  "version": "1.0",
  "event": "whatsapp.inbound",
  "eventId": "3f9e2b8c-1a2d-4e3f-9b1a-2c3d4e5f6a7b",
  "timestamp": "2026-08-03T14:22:05.123Z",
  "locationId": "loc_2f9a41",
  "payload": { }
}
```

| Campo        | Tipo                | Descrição                                                                      |
| ------------ | ------------------- | ------------------------------------------------------------------------------ |
| `version`    | `string`            | Sempre `"1.0"`.                                                                |
| `event`      | `string`            | O nome do evento, correspondente ao que você selecionou ao criar a assinatura. |
| `eventId`    | `string`            | ID único para esta entrega. Use-o para deduplicar eventos reenviados.          |
| `timestamp`  | `string` (ISO 8601) | Quando o evento foi despachado.                                                |
| `locationId` | `string`            | A location à qual o evento pertence.                                           |
| `payload`    | `object`            | Dados específicos do evento. Veja Payloads dos Eventos abaixo.                 |

### Cabeçalhos

```text theme={null}
Content-Type: application/json
X-WA-Event-Id: <eventId>
X-WA-Timestamp: <unix timestamp, ms>
```

<Note>
  `X-WA-Event-Id` corresponde ao `eventId` no corpo.
</Note>

## Payloads dos Eventos

O objeto `payload` difere de acordo com o canal e o tipo de evento. `message.media[].type` é sempre um dos seguintes: `image`, `video`, `audio`, `document`, `file`, ou `unknown`.

### Mensagens de entrada

`whatsapp.inbound`, `imessage.inbound`, `sms.inbound` - disparado quando um contato envia uma mensagem para um dos seus números conectados.

<Tabs>
  <Tab title="WhatsApp">
    ```json theme={null}
    {
      "messageId": "wamid.HBgLMTU1NTk4NzY1NDMV...",
      "locationId": "loc_2f9a41",
      "device": { "number": "15551230000", "name": "Recepção" },
      "contact": { "id": "contact_7be31c", "name": "Jane Doe", "number": "15559876543" },
      "message": {
        "text": "Oi, meu pedido está pronto?",
        "media": [{ "url": "https://cdn.example.com/img.jpg", "type": "image" }]
      },
      "transcribedAudio": "Texto transcrito de uma nota de voz, quando presente"
    }
    ```
  </Tab>

  <Tab title="iMessage">
    ```json theme={null}
    {
      "messageId": "msg_9d41ab",
      "locationId": "loc_2f9a41",
      "device": { "number": "15551230000" },
      "contact": { "id": "contact_7be31c", "name": "Jane Doe", "number": "15559876543" },
      "message": { "text": "Estou a caminho, 5 min" },
      "meta": { "transcribedAudio": "Texto transcrito de uma nota de voz, quando presente" }
    }
    ```
  </Tab>

  <Tab title="SMS">
    ```json theme={null}
    {
      "messageId": "msg_4e17cd",
      "locationId": "loc_2f9a41",
      "device": { "number": "15551230000" },
      "contact": { "id": "contact_7be31c", "name": "Jane Doe", "number": "15559876543" },
      "message": { "text": "Posso remarcar para sexta-feira?" }
    }
    ```
  </Tab>
</Tabs>

| Campo                                | Tipo     | Notas                                                                                                                                   |
| ------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `messageId`                          | `string` | ID da mensagem do provedor.                                                                                                             |
| `locationId`                         | `string` | A location à qual o evento pertence.                                                                                                    |
| `device.number`                      | `string` | O número conectado que recebeu a mensagem.                                                                                              |
| `device.name`                        | `string` | Opcional.                                                                                                                               |
| `contact.id`                         | `string` | ID do contato no CRM, se o remetente já for um contato conhecido.                                                                       |
| `contact.name`                       | `string` | Opcional.                                                                                                                               |
| `contact.number`                     | `string` | Número do remetente. Opcional no WhatsApp, onde um remetente pode ser identificado apenas pelo `lid`.                                   |
| `contact.lid` / `contact.waUsername` | `string` | Somente WhatsApp. Campos de identidade opcionais, presentes quando o WhatsApp os envia.                                                 |
| `message.text`                       | `string` | Opcional. Ausente em mensagens só com mídia.                                                                                            |
| `message.media`                      | `array`  | Cada item tem `url` e `type`. Pode estar ausente, ou ser um array vazio, quando não há mídia.                                           |
| `transcribedAudio`                   | `string` | Transcrição de uma nota de voz, quando a transcrição está habilitada.                                                                   |
| `ctwa`                               | `object` | Somente WhatsApp. Metadados de anúncio click-to-WhatsApp, presente apenas quando a conversa começou a partir de um anúncio do WhatsApp. |

<Note>
  `transcribedAudio` fica no nível superior no WhatsApp, mas aninhado em `meta.transcribedAudio` no iMessage e SMS.
</Note>

### Mensagens de saída

`whatsapp.outbound`, `imessage.outbound`, `sms.outbound` - disparado quando uma mensagem é enviada de um número conectado, seja digitada no dispositivo ou enviada pelo CRM.

```json theme={null}
{
  "messageId": "wamid.HBgLMTU1NTk4NzY1NDMV...",
  "source": "crm",
  "contact": { "id": "contact_7be31c", "number": "15559876543" },
  "message": { "text": "Seu pedido está pronto para retirada!" },
  "device": { "number": "15551230000", "name": "Recepção", "instanceIndex": 0 },
  "locationId": "loc_2f9a41",
  "timestamp": "2026-08-03T14:25:10.500Z"
}
```

| Campo                                | Tipo                | Notas                                                                                                                               |
| ------------------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `messageId`                          | `string`            |                                                                                                                                     |
| `locationId`                         | `string`            | A location à qual o evento pertence.                                                                                                |
| `source`                             | `string`            | Como a mensagem foi enviada: `crm` (pelo CRM ou por uma automação), `device` (digitada no telefone/app conectado), `n8n`, ou `api`. |
| `contact.id`                         | `string`            |                                                                                                                                     |
| `contact.number`                     | `string`            |                                                                                                                                     |
| `contact.name`                       | `string`            | Opcional. Geralmente ausente em envios iniciados pelo CRM.                                                                          |
| `contact.lid` / `contact.waUsername` | `string`            | Somente WhatsApp. Campos de identidade opcionais, iguais aos de entrada.                                                            |
| `message.text` / `message.media`     |                     | Mesma estrutura das mensagens de entrada.                                                                                           |
| `device.number`                      | `string`            | O número conectado que enviou.                                                                                                      |
| `device.name`                        | `string`            | Opcional.                                                                                                                           |
| `device.instanceIndex`               | `number`            | Opcional. A instância conectada que enviou.                                                                                         |
| `timestamp`                          | `string` (ISO 8601) |                                                                                                                                     |

### Falha na mensagem

`message.failed` - disparado quando uma mensagem de saída em qualquer canal não pôde ser entregue após novas tentativas.

```json theme={null}
{
  "messageId": "msg_7c6b5a",
  "contactId": "contact_7be31c",
  "message": "Oi, dando um retorno sobre seu agendamento",
  "channelType": "whatsapp",
  "error": {
    "code": "109",
    "type": "WhatsAppFailure",
    "message": "Could not send the message. Please contact Custom Provider Support team"
  },
  "device": { "instanceIndex": 2, "phoneNumber": "15551230000" },
  "receiver": { "phoneNumber": "15559876543", "contactId": "contact_7be31c" },
  "locationId": "loc_2f9a41",
  "timestamp": "2026-08-03T14:30:00.000Z"
}
```

| Campo                               | Tipo                                    | Notas                                                      |
| ----------------------------------- | --------------------------------------- | ---------------------------------------------------------- |
| `messageId`                         | `string`                                |                                                            |
| `contactId`                         | `string`                                | Opcional.                                                  |
| `message`                           | `string`                                | Prévia opcional do corpo da mensagem que falhou ao enviar. |
| `channelType`                       | `"whatsapp"` \| `"imessage"` \| `"sms"` | Opcional.                                                  |
| `error.code` / `.type` / `.message` | `string`                                | Detalhes da falha.                                         |
| `device.instanceIndex`              | `number` \| `null`                      |                                                            |
| `device.phoneNumber`                | `string` \| `null`                      | O número conectado que tentou o envio.                     |
| `receiver.phoneNumber`              | `string`                                | Número do destinatário.                                    |
| `receiver.contactId`                | `string`                                | Opcional.                                                  |
| `locationId`                        | `string`                                | A location à qual o evento pertence.                       |
| `timestamp`                         | `string` (ISO 8601)                     | Quando a falha foi registrada.                             |

`error.code` indica por que o envio falhou. Veja [Códigos de Erro](/pt-BR/automation/triggers/message-failed#c%C3%B3digos-de-erro) para a lista completa e o que fazer em cada caso.

<Note>
  Novos códigos podem ser adicionados com o tempo, então trate códigos não reconhecidos como uma falha genérica em vez de assumir uma lista fixa.
</Note>

## Boas Práticas

* **Use uma assinatura por integração.** Mantém os logs e a rotação simples.
* **Verifique com o ping de teste** antes de confiar em uma assinatura em produção.
* **Retorne `2xx` rapidamente** - delegue o trabalho lento a uma fila em segundo plano no seu handler.
* **Seja idempotente.** Webhooks podem ocasionalmente ser reentregues.
* **Delimite por canal.** Não se inscreva em eventos que você não vai processar.

## Gerenciando Assinaturas

Na seção **Webhooks** das Configurações da Location, você pode:

* Ver todas as assinaturas ativas e a data de criação
* Excluir uma assinatura de que você não precisa mais
* Criar assinaturas adicionais para endpoints separados

## Solução de Problemas

<AccordionGroup>
  <Accordion title="O ping de teste nunca chegou">
    * Confirme que seu endpoint está acessível publicamente (sem localhost / IPs privados)
    * Verifique se ele aceita `POST` e retorna `2xx`
    * Confira se regras de firewall/WAF não estão bloqueando o IP
  </Accordion>

  <Accordion title="Os eventos pararam de disparar">
    * Certifique-se de que a assinatura não foi excluída
    * Confirme que a location ainda tem uma instância conectada para o canal
    * Verifique os logs do seu endpoint em busca de respostas `5xx` (entregas com falha são retentadas algumas vezes e depois descartadas)
  </Accordion>

  <Accordion title="Eventos duplicados">
    Os webhooks têm entrega "pelo menos uma vez" (at-least-once). Use o `eventId` de nível superior (também enviado como o cabeçalho `X-WA-Event-Id`) para deduplicar do seu lado.
  </Accordion>
</AccordionGroup>
