Sign inGet started

Recebendo mensagens WhatsApp

Mensagens recebidas ficam no mesmo recurso que as enviadas, sem um endpoint de caixa de entrada separado para consultar. Leia-as pela lista de mensagens no dashboard, ou pela API com GET /v1/whatsapp/messages/{id} depois de filtrar a lista para recebidas.
Toda mensagem recebida estende a janela de atendimento ao cliente para 24 horas após o timestamp da própria mensagem, que é o que torna uma resposta livre sua entregável. Uma mensagem que chega ao Bird com atraso carrega a janela que o contato realmente concedeu, e um prazo posterior já registrado nunca é encurtado.

O que uma mensagem recebida contém

Toda mensagem recebida compartilha um envelope: um id, direction: "inbound", o contato em from, seu próprio número em to, um status de received e um created_at. Exatamente um campo de conteúdo acompanha o envelope, indicando o que o contato enviou:
Exemplo de código
{
  "id": "wam_01kya19eknftrs2s6p82asmvnh",
  "direction": "inbound",
  "from": { "phone_number": "+14155550100" },
  "to": { "phone_number": "+13124495569" },
  "status": "received",
  "text": { "body": "Is my order out for delivery yet?" },
  "created_at": "2026-08-25T09:04:11Z"
}
from identifica o contato por qualquer identidade que WhatsApp reporte: um phone_number E.164, um bsuid, ou ambos, além de username e display_name que o contato publica. Um contato que adotou um nome de usuário WhatsApp pode entrar em contato com você sem número de telefone; veja IDs de usuário com escopo de negócio para saber o que armazenar e como solicitar um número.
Um desses campos de conteúdo, um arm, contém o que o contato enviou, e exatamente um arm é preenchido em qualquer mensagem. Cada um tem sua própria página, com o formato de leitura, o payload whatsapp.received e o que observar:
CampoO que uma mensagem recebida contém
textbody, a mensagem que o contato digitou
imageUm id, url, mime_type e qualquer caption
videoOs mesmos campos de mídia, mais qualquer caption
audioOs mesmos campos de mídia, mais voice em uma nota de voz; não existe legenda
stickerOs mesmos campos de mídia, mais animated
documentOs mesmos campos de mídia, mais qualquer filename e caption
locationlatitude e longitude, e às vezes name, address ou um url
contact_cardsUm ou mais cartões de contato que o contato compartilhou
interactive_replyO slug e o text do botão ou linha que o contato tocou
unsupportedO tipo de conteúdo WhatsApp que o API não modela, como um pedido
Dois toques chegam em um arm que você talvez não espere. Uma solicitação de localização responde como um location recebido comum, e uma solicitação de informações de contato responde como contact_cards, então uma integração que observa apenas interactive_reply para um toque perde ambos.

Baixando mídia recebida

Um image, video, audio, sticker ou document recebido chega como uma referência a um arquivo que Bird armazenou, e não como o arquivo em si:
Exemplo de código
{
  "image": {
    "id": "waf_01kyb2m4xq7whs0d8n3prv6tez",
    "url": "https://platform.bird.com/v1/whatsapp/messages/wam_01kya19eknftrs2s6p82asmvnh/media/waf_01kyb2m4xq7whs0d8n3prv6tez",
    "mime_type": "image/jpeg",
    "caption": "Is this the right part?"
  }
}
Baixe os bytes com o método de mídia do canal, passando o id da mensagem e o id da mídia:
const media = await bird.whatsapp.messages.media(
  "wam_01kya19eknftrs2s6p82asmvnh",
  "waf_01kyb2m4xq7whs0d8n3prv6tez",
);
console.log(media.contentType, media.contentLength);
Você recebe os bytes de volta com o mime_type de armazenamento declarado para eles. Um id que Bird não reconhece retorna 404, e uma mensagem enviada não tem mídia armazenada para servir.
Uma mensagem pode ser lida por 30 dias após a chegada, e sua mídia nunca sobrevive a ela. Esse endpoint lê a mensagem antes de servir o arquivo, então, quando essa janela expira, ambos respondem 404. Armazene qualquer arquivo de que você precise por mais tempo enquanto a mensagem ainda é legível. O único caso que encerra antes é os bytes armazenados expirarem antes da janela: a busca responde 410 E15021, e a mensagem ainda é lida com o mime_type e o caption da mídia.
Por baixo dos panos, esse endpoint responde 302 com uma URL pré-assinada válida por 15 minutos. Os SDKs e a CLI fazem esse redirecionamento por você. Chamando diretamente, a URL pré-assinada carrega sua própria credencial, então a solicitação redirecionada não deve enviar também o header Authorization. Enviar ambos falha. curl -L remove o header em um redirecionamento cross-host automaticamente; um cliente que encaminha headers literalmente precisa buscar o Location como uma solicitação separada e não autenticada.

Respostas com citação

in_reply_to_message_id identifica a mensagem que uma mensagem recebida responde, quando WhatsApp a marca como resposta:
Exemplo de código
{
  "id": "wam_01kyb2m4xq7whs0d8n3prv6tez",
  "direction": "inbound",
  "in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
  "text": { "body": "Yes, that one" }
}
WhatsApp não marca toda resposta, e uma não marcada não carrega nenhum ID. O campo também é omitido quando a mensagem citada não pode ser associada a uma que Bird mantém: uma mensagem enviada antes de este espaço de trabalho começar a registrá-las, ou uma além dos 15 dias que Bird mantém os ids de mensagem do próprio WhatsApp. Uma ausência omite o campo em vez de reportar um, o que se lê igual a uma resposta que não responde a nada.
Trate o campo como uma dica, não como uma chave. metadata no seu próprio envio não ajuda aqui, porque ele permanece na sua mensagem e nunca viaja até a resposta do contato, então uma integração que precisa saber a qual pergunta uma resposta pertence rastreia a pergunta que ela mesma fez por último àquele contato. Veja Citando uma mensagem para o lado de envio.

O webhook

Inscreva-se em whatsapp.received para agir sobre uma mensagem recebida assim que ela chega, em vez de consultar a lista. O payload carrega o conteúdo sobre o envelope do evento, então um endpoint não precisa de uma leitura de acompanhamento:
Exemplo de código
{
  "type": "whatsapp.received",
  "timestamp": "2026-08-25T09:04:11.118Z",
  "data": {
    "whatsapp_id": "wam_01kyb2m4xq7whs0d8n3prv6tez",
    "workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
    "direction": "inbound",
    "from": { "phone_number": "+14155550100", "display_name": "Alex Rivera" },
    "to": { "phone_number": "+13124495569" },
    "in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
    "interactive_reply": {
      "type": "button",
      "button": { "slug": "cancel-booking", "text": "Cancel" }
    },
    "tags": null,
    "metadata": null
  }
}
Veja eventos WhatsApp para o envelope completo e o restante da lista de eventos.

Próximos passos