---
title: "Webhook de WhatsApp WhatsMeow"
description: "Mensagens, recibos de leitura, chamadas, grupos e conexão — com o nome do evento vindo junto, e um filtro para escolher o que chega."
lang: pt-BR
canonical: https://doc.apibrasil.io/webhooks/api-whatsapp-whatsmeow
markdown: https://doc.apibrasil.io/webhooks/api-whatsapp-whatsmeow.md
source: apibrasil-documentation
---

# Webhook de WhatsApp WhatsMeow

> Mensagens, recibos de leitura, chamadas, grupos e conexão — com o nome do evento vindo junto, e um filtro para escolher o que chega.

É o único canal de WhatsApp em que o aviso diz qual evento ele é, e o único em que você escolhe o que quer receber: subscribe filtra na origem, então o seu endpoint só é acordado pelo que interessa.

## Como receber

A URL é registrada no CONNECT da instância e quem chama é o evolution-go, direto — sem relay da APIBrasil no caminho. O corpo tem cinco campos e o nome do evento vem em event, em PascalCase. Você escolhe o que recebe em subscribe, que aceita 16 categorias além de ALL, o padrão.

**Onde registrar a URL e o que cai nela**

| Campo | O que recebe | Eventos |
| --- | --- | --- |
| `webhook_wh_qr_code` | TODOS os eventos. O dispositivo tem quatro campos de URL, mas este canal usa só o primeiro preenchido — ver a ressalva sobre a ordem. | todos os eventos do canal |

Os eventos deste canal são independentes: não há ordem entre eles.

## Eventos (18)

### `Message` — Mensagem recebida

**Quando dispara:** Quando chega qualquer mensagem. É também o evento das mensagens não decifráveis (UndecryptableMessage), que chegam com o mesmo nome. Liberado pelas categorias MESSAGE, GROUP e NEWSLETTER — a de grupo e a de canal reaproveitam este mesmo evento.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Message" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O evento events.Message do whatsmeow, cru: Info com remetente, id e horário, e Message com o conteúdo. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Message",
    "data": {
      "…": "o events.Message do whatsmeow, com Info e Message"
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `QRCode` — QR Code para parear

**Quando dispara:** Quando a instância precisa ser autenticada. É o único evento cujo data é montado pelo serviço, e não o struct cru do whatsmeow — por isso os campos abaixo são exatos. Liberado pela categoria QRCODE.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "QRCode", em PascalCase. |
| `data.qrcode` | string | A imagem em base64, pronta para exibir. |
| `data.code` | string | O conteúdo do código, para gerar a imagem você mesmo. |
| `data.count` | number | Qual tentativa é esta. O QR expira e é regerado várias vezes. |
| `data.maxCount` | number | Quantas tentativas antes de desistir. Chegando ao teto, a conexão falha. |
| `instanceToken` | string | O token da instância, no corpo. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "QRCode",
    "data": {
      "qrcode": "data:image/png;base64,…",
      "code": "2@Xk9…",
      "count": 1,
      "maxCount": 6
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `Receipt` — Entregue, lida ou reproduzida

**Quando dispara:** Quando uma mensagem sua muda de estado no aparelho do destinatário. Liberado pela categoria READ_RECEIPT em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Receipt" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.Receipt do whatsmeow: os ids das mensagens, o tipo do recibo e quem confirmou. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Receipt",
    "data": {
      "…": "O events.Receipt do whatsmeow: os ids das mensagens, o tipo do recibo e quem confirmou."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `Connected` — A instância conectou

**Quando dispara:** Quando a sessão fica de pé. O evento PushNameSetting também chega com este mesmo nome. Liberado pela categoria CONNECTION em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Connected" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O evento de conexão do whatsmeow. Vazio ou quase — o que importa é ter chegado. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Connected",
    "data": {
      "…": "O evento de conexão do whatsmeow. Vazio ou quase — o que importa é ter chegado."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `Disconnected` — A instância caiu

**Quando dispara:** Quando a conexão se perde. É o aviso que dispara a sua reconexão. Liberado pela categoria CONNECTION em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Disconnected" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.Disconnected do whatsmeow. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Disconnected",
    "data": {
      "…": "O events.Disconnected do whatsmeow."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `LoggedOut` — A sessão foi desconectada do aparelho

**Quando dispara:** Quando alguém desvincula o aparelho pelo WhatsApp. Diferente de Disconnected: aqui reconectar não resolve, é preciso parear de novo. Liberado pela categoria CONNECTION em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "LoggedOut" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.LoggedOut do whatsmeow, com o motivo da desconexão. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "LoggedOut",
    "data": {
      "…": "O events.LoggedOut do whatsmeow, com o motivo da desconexão."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `TemporaryBan` — O número foi banido temporariamente

**Quando dispara:** Quando o WhatsApp aplica um bloqueio temporário ao número. É o aviso mais caro do canal para ignorar — enquanto durar, nada é enviado. Liberado pela categoria CONNECTION em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "TemporaryBan" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.TemporaryBan do whatsmeow, com o código e a duração do bloqueio. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "TemporaryBan",
    "data": {
      "…": "O events.TemporaryBan do whatsmeow, com o código e a duração do bloqueio."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `PairSuccess` — Pareamento concluído

**Quando dispara:** Quando a leitura do QR Code termina e o aparelho é vinculado. Liberado pela categoria CONNECTION em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "PairSuccess" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.PairSuccess do whatsmeow, com o JID que acabou de parear. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "PairSuccess",
    "data": {
      "…": "O events.PairSuccess do whatsmeow, com o JID que acabou de parear."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `CallOffer` — Chamada recebida

**Quando dispara:** Quando alguém liga. A categoria CALL cobre também CallAccept, CallTerminate, CallOfferNotice e CallRelayLatency, cada um com o seu próprio nome em event. Liberado pela categoria CALL em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "CallOffer" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.CallOffer do whatsmeow: quem ligou, quando e o id da chamada. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "CallOffer",
    "data": {
      "…": "O events.CallOffer do whatsmeow: quem ligou, quando e o id da chamada."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `GroupInfo` — Um grupo mudou

**Quando dispara:** Quando muda nome, descrição, participantes ou permissões de um grupo. JoinedGroup, na mesma categoria, avisa que você entrou em um. Liberado pela categoria GROUP em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "GroupInfo" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.GroupInfo do whatsmeow, com o que mudou no grupo. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "GroupInfo",
    "data": {
      "…": "O events.GroupInfo do whatsmeow, com o que mudou no grupo."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `Contact` — Um contato mudou

**Quando dispara:** Quando dados de um contato são atualizados. PushName, na mesma categoria, avisa a troca do nome de exibição. Liberado pela categoria CONTACT em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Contact" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.Contact do whatsmeow. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Contact",
    "data": {
      "…": "O events.Contact do whatsmeow."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `ChatPresence` — Digitando ou gravando

**Quando dispara:** Quando o contato começa ou para de digitar numa conversa. Archive, na mesma categoria, avisa que a conversa foi arquivada. Liberado pela categoria CHAT_PRESENCE em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "ChatPresence" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.ChatPresence do whatsmeow: a conversa, o estado e por quanto tempo. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "ChatPresence",
    "data": {
      "…": "O events.ChatPresence do whatsmeow: a conversa, o estado e por quanto tempo."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `Presence` — Online ou visto por último

**Quando dispara:** Quando um contato fica online ou sai. É o evento mais frequente do canal. Liberado pela categoria PRESENCE em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Presence" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.Presence do whatsmeow. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Presence",
    "data": {
      "…": "O events.Presence do whatsmeow."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `HistorySync` — Sincronização de histórico

**Quando dispara:** Quando o WhatsApp envia lotes do histórico — normalmente logo depois de parear. Os payloads são grandes; assine esta categoria só se for usá-los. Liberado pela categoria HISTORY_SYNC em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "HistorySync" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.HistorySync do whatsmeow, com o lote de conversas e mensagens. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "HistorySync",
    "data": {
      "…": "O events.HistorySync do whatsmeow, com o lote de conversas e mensagens."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `Picture` — Foto de perfil alterada

**Quando dispara:** Quando um contato ou grupo troca a foto. Liberado pela categoria PICTURE em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "Picture" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.Picture do whatsmeow, com o JID e o id da nova foto. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "Picture",
    "data": {
      "…": "O events.Picture do whatsmeow, com o JID e o id da nova foto."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `LabelEdit` — Etiqueta criada ou alterada

**Quando dispara:** Quando uma etiqueta do WhatsApp Business muda. A categoria LABEL cobre também LabelAssociationChat e LabelAssociationMessage, que ligam a etiqueta a uma conversa ou mensagem. Liberado pela categoria LABEL em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "LabelEdit" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.LabelEdit do whatsmeow. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "LabelEdit",
    "data": {
      "…": "O events.LabelEdit do whatsmeow."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `NewsletterJoin` — Entrou num canal

**Quando dispara:** Quando a instância entra num canal do WhatsApp. NewsletterLeave, na mesma categoria, avisa a saída. Liberado pela categoria NEWSLETTER em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "NewsletterJoin" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.NewsletterJoin do whatsmeow. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "NewsletterJoin",
    "data": {
      "…": "O events.NewsletterJoin do whatsmeow."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

### `UserAbout` — Recado alterado

**Quando dispara:** Quando um contato muda o texto de recado do perfil. Liberado pela categoria USER_ABOUT em subscribe.

**Campos**

| Nome | Tipo | Significado |
| --- | --- | --- |
| `event` | string | "UserAbout" — em PascalCase, NÃO na caixa alta usada em subscribe. |
| `data` | object | O events.UserAbout do whatsmeow. |
| `instanceToken` | string | O token da instância, DENTRO do corpo. É por ele que se confere a origem — não há assinatura neste canal. |
| `instanceId` | string | O id do usuário da instância. |
| `instanceName` | string | O nome da instância. |

**Corpo de exemplo, como chega**

```json
[
  {
    "event": "UserAbout",
    "data": {
      "…": "O events.UserAbout do whatsmeow."
    },
    "instanceToken": "<token da instância>",
    "instanceId": "<id do usuário>",
    "instanceName": "apibrasil-whatsmeow"
  }
]
```

## O que costuma pegar

- **É UMA URL só, e ela é escolhida por ordem de preenchimento** — O gateway pega a primeira não vazia entre webhook_wh_qr_code, webhook_wh_connect, webhook_wh_message e webhook_wh_status — nessa ordem. Preencher os quatro, como se faz no Wpp, manda tudo para o de QR Code. Preencha só o que você quer usar.
- **event vem em PascalCase; subscribe usa CAIXA ALTA** — São dois vocabulários no mesmo canal. Você assina "MESSAGE", "READ_RECEIPT", "CONNECTION" — e recebe event valendo "Message", "Receipt", "Connected". Comparar event === "MESSAGE" nunca casa, e a falha é silenciosa: o webhook chega e o seu roteador ignora.
- **A documentação oficial e o código discordam neste ponto** — O wiki do evolution-go mostra um exemplo com "event": "MESSAGE" e um envelope de três campos. O código monta "event": "Message" e cinco campos, com instanceToken, instanceId e instanceName. O que está aqui é o do código, que é o que chega.
- **A URL é registrada no CONNECT, não no painel nem no envio** — O webhookUrl vai no payload da ação de conectar a instância. Trocar a URL depois exige conectar de novo — não basta editar o campo no dispositivo.
- **Sem assinatura: quem identifica é o instanceToken, no corpo** — Não há HMAC como no Wpp nem cabeçalho próprio como no Baileys. O único header é Content-Type. A autenticidade se confere comparando o instanceToken do corpo com o seu, e a comparação deve ser de tempo constante. Como ele é um segredo que trafega no payload, HTTPS aqui não é recomendação.
- **Cinco tentativas, e nenhum limite de tempo do lado de lá** — O produtor tenta até 5 vezes, com 30 segundos entre elas, e aceita qualquer 2xx como sucesso — não só 200. Em compensação o cliente HTTP dele não tem timeout: um endpoint que não responde pode segurar a conexão indefinidamente.

## Boas práticas

- **Compare o instanceToken antes de confiar** — É a única prova de origem deste canal — não há assinatura nem cabeçalho próprio. Compare com tempo constante e recuse o que não bater, senão a sua URL aceita qualquer POST de quem a descobrir.
- **Roteie por event em PascalCase** — Você assina MESSAGE e recebe "Message". Um switch escrito com os nomes de subscribe não casa com nada, e o efeito é o endpoint receber tudo e tratar nada.
- **Filtre em subscribe, não no seu código** — Presence e HistorySync são os eventos mais volumosos do WhatsApp. Recebê-los para descartar no if gasta banda, CPU e as cinco tentativas do produtor. Assine só as categorias que você usa.
- **Responda 2xx e responda rápido** — Qualquer 2xx conta como sucesso. Sem ele são 5 tentativas espaçadas de 30 segundos para o MESMO evento — um endpoint lento vira cinco cópias em dois minutos e meio.

## Receptores de exemplo

**Node**

```node
app.post("/webhook/whatsmeow", express.json(), (req, res) => {
  const { event, data, instanceToken, instanceName } = req.body

  // Única prova de origem deste canal: não há assinatura.
  if (instanceToken !== INSTANCE_TOKEN) return res.sendStatus(401)

  res.sendStatus(200) // qualquer 2xx serve; sem ele, 5 tentativas a cada 30s

  // ATENÇÃO: event vem em PascalCase, não na caixa alta do subscribe.
  switch (event) {
    case "Message":
      console.log("mensagem recebida", data)
      break
    case "Receipt":
      console.log("recibo de leitura", data)
      break
    case "QRCode":
      exibirQrCode(data.qrcode) // `${data.count}/${data.maxCount}` tentativas
      break
    case "LoggedOut":
      // Diferente de Disconnected: aqui é preciso parear de novo.
      pedirNovoPareamento(instanceName)
      break
    case "TemporaryBan":
      alertarBanimento(instanceName, data)
      break
    default:
      console.warn("evento WhatsMeow não tratado:", event)
  }
})
```

**Python**

```python
import hmac

@app.post("/webhook/whatsmeow")
def webhook_whatsmeow():
    corpo = request.get_json(force=True)

    # Única prova de origem deste canal: não há assinatura.
    if not hmac.compare_digest(corpo.get("instanceToken", ""), INSTANCE_TOKEN):
        return "", 401

    evento = corpo["event"]   # PascalCase, não a caixa alta do subscribe
    data = corpo["data"]

    if evento == "Message":
        print("mensagem recebida", data)
    elif evento == "Receipt":
        print("recibo de leitura", data)
    elif evento == "QRCode":
        exibir_qrcode(data["qrcode"])  # data['count'] de data['maxCount']
    elif evento == "LoggedOut":
        # Diferente de Disconnected: aqui é preciso parear de novo.
        pedir_novo_pareamento(corpo["instanceName"])
    elif evento == "TemporaryBan":
        alertar_banimento(corpo["instanceName"], data)
    else:
        print("evento WhatsMeow não tratado:", evento)

    return "", 200
```

**PHP**

```php
<?php

$corpo = json_decode(file_get_contents('php://input'), true);

// Única prova de origem deste canal: não há assinatura.
if (!hash_equals(INSTANCE_TOKEN, $corpo['instanceToken'] ?? '')) {
    http_response_code(401);
    exit;
}

http_response_code(200);

// ATENÇÃO: event vem em PascalCase, não na caixa alta do subscribe.
switch ($corpo['event']) {
    case 'Message':
        error_log('mensagem recebida');
        break;
    case 'Receipt':
        error_log('recibo de leitura');
        break;
    case 'QRCode':
        exibirQrCode($corpo['data']['qrcode']);
        break;
    case 'LoggedOut':
        // Diferente de Disconnected: aqui é preciso parear de novo.
        pedirNovoPareamento($corpo['instanceName']);
        break;
    case 'TemporaryBan':
        alertarBanimento($corpo['instanceName'], $corpo['data']);
        break;
    default:
        error_log('evento WhatsMeow não tratado: ' . $corpo['event']);
}
```

## Ver também

- Webhooks: [Webhooks](https://doc.apibrasil.io/webhooks.md)
- Índice da documentação: https://doc.apibrasil.io/llms.txt
- Versão HTML desta página: https://doc.apibrasil.io/webhooks/api-whatsapp-whatsmeow
