Pular para o conteúdo principal

Tipos de mensagem — envio e recebimento

Esta referência detalha o que você envia (request) e o que você recebe (o payload do webhook message.received e do histórico em GET /conversations/{jid}/messages) para cada tipo. Use isso para consumir as informações conforme a sua necessidade.

Campos comuns de todo recebido

Todo message.received traz no envelope: type, instance_id (o número que recebeu), sender ({ jid, lid, name }), e no payload: message_id, wa_message_id, from, body, e quoted_id quando for resposta. Telefones são gravados como o JID de telefone do cliente (conversa unificada entre todos os seus números).


Texto

EnvioPOST /messages/text

{ "to": "+5511999999999", "body": "Olá 👋" }

Recebido (type: "text")

{ "type": "text", "body": "Olá 👋", "from": "[email protected]" }

Imagem · Vídeo · Documento · Áudio · Sticker

EnvioPOST /messages/{image|video|document|audio|sticker}

{ "to": "+5511999999999",
"media": { "url": "https://.../foto.jpg", "caption": "Olha isso", "filename": "foto.jpg", "mimetype": "image/jpeg", "ptt": false } }
  • url ou base64. ptt: true (áudio) = nota de voz. caption vale para image/video/document.

Recebido (type: "image" | "video" | "audio" | "document" | "sticker")

{ "type": "image",
"body": "Olha isso", // = caption
"media": {
"id": "uuid",
"url": "https://api.bzapper.com.br/media/uuid?exp=...&sig=...",
"mime_type": "image/jpeg", "filename": "foto.jpg", "size": 84211
} }
Mídia de conversa é PRIVADA

A mídia recebida não é pública: vai para um bucket privado (files.bzapper.com.br, separado dos assets públicos em assets.bzapper.com.br). A media.url é uma URL pré-assinada SigV4 com TTL (MEDIA_URL_TTL, ~24h, configurável — ver config.go) — ela expira, então não a armazene.

A referência estável é GET /media/{id} (com exp+sig): a API responde 302 redirecionando para uma URL pré-assinada fresca, e o cliente baixa direto do Spaces/CDN. Sempre que precisar do arquivo, refaça esse GET (não guarde a media.url expirada). audio com ptt é nota de voz.

Localização

EnvioPOST /messages/location

{ "to": "+5511999999999", "latitude": -23.561, "longitude": -46.656, "name": "Av. Paulista", "address": "São Paulo" }

Recebido (type: "location")

{ "type": "location", "body": "Av. Paulista", "latitude": -23.561, "longitude": -46.656 }

Contato (vCard)

EnvioPOST /messages/contact

{ "to": "+5511999999999", "contact_name": "Suporte", "contact_vcard": "BEGIN:VCARD..." }
  • Sem contact_vcard, geramos um vCard simples a partir do nome/telefone.

Recebido (type: "contact") — body = nome exibido.

Reação (emoji)

EnvioPOST /messages/reaction

{ "to": "+5511999999999", "quoted_message_id": "<wa_message_id>", "emoji": "❤️" }

Recebido (type: "reaction") — body = emoji; quoted_id = mensagem reagida.

Enquete (poll)

EnvioPOST /messages/poll

{ "to": "+5511999999999", "name": "Qual horário?", "options": ["Manhã", "Tarde", "Noite"], "selectable_count": 1 }

Recebido — a enquete (type: "poll")

{ "type": "poll", "body": "Qual horário?",
"poll": { "name": "Qual horário?", "options": ["Manhã", "Tarde", "Noite"] } }

Recebido — o VOTO (type: "poll_vote")

{ "type": "poll_vote",
"body": "Tarde",
"poll_vote": {
"poll_message_id": "<wa_message_id da enquete>",
"selected": ["Tarde"] // opções escolhidas, já resolvidas
} }

O voto chega criptografado pelo WhatsApp (apenas hashes). O bZapper decifra e resolve os hashes contra as opções da enquete original, entregando os nomes em poll_vote.selected. Correlacione com a enquete pelo poll_message_id. Voto múltiplo (selectable_count > 1) traz vários itens em selected.

Botões e Listas (menu)

EnvioPOST /messages/{buttons|list}

{ "to": "+5511999999999", "body": "Confirma o pedido?", "buttons": [{ "id": "sim", "title": "Sim" }, { "id": "nao", "title": "Não" }] }
Comportamento

O WhatsApp restringe botões/listas interativos a contas da API oficial. Para remetentes não-oficiais, o bZapper envia automaticamente um menu de texto numerado equivalente (fallback estável que sempre entrega). A resposta do cliente chega como type: "text" com o texto/numero escolhido — trate como texto comum.

OTP (código de verificação)

EnvioPOST /messages/otp

{ "to": "+5511999999999", "code": "738291", "expiry_minutes": 5 }

O OTP vai em duas mensagens no WhatsApp: um texto de contexto + um balão só com o código (fácil de copiar com long-press, em qualquer aparelho). É 1 OTP lógico e conta como 1 envio para cobrança.

  • Se você omitir body, a API gera o texto no idioma da conta com variações aleatórias (anti-ban — repetir texto idêntico em massa facilita o fingerprint do WhatsApp). expiry_minutes (opcional) só é mencionado no texto.
  • O código nunca é persistido em claro nem exibido no inbox: guardamos apenas uma versão mascarada (ex.: ••••91) para auditoria/UX, e o echoguard impede que o código apareça na transcrição.
Segurança do OTP

Trate o code como segredo. O bZapper não o devolve em nenhuma listagem de conversa nem em webhooks de status — só você (que o gerou) o conhece.


Tabela rápida (tipos recebidos)

typeCampos-chave no payload
textbody
image/video/audio/document/stickerbody (caption), media.{url,mime_type,filename,size}
locationlatitude, longitude, body (nome)
contactbody (nome)
reactionbody (emoji), quoted_id
pollpoll.{name,options}
poll_votepoll_vote.{poll_message_id,selected[]}, body

otp é só de envio (POST /messages/otp) — o código nunca volta no recebimento/inbox.

Veja também Webhooks (assinatura/entrega) e Atendimento (conversa unificada por cliente).