Mensagens interativas do WhatsApp
Uma mensagem interativa é um texto de corpo mais algo para o destinatário tocar: um botão WhatsApp, um menu, um link, um card ou uma solicitação de localização ou dados de contato. Quando uma resposta com template exige interpretar texto livre, um menu WhatsApp ou um conjunto de botões WhatsApp oferece ao destinatário opções fixas e devolve a você um valor que você definiu. Esta página cobre o que os seis tipos têm em comum; a página de cada tipo cobre seu formato no fio e seus próprios limites.
Os seis tipos
| Tipo | Bird interactive.type | Cabeçalho | Rodapé | Corpo máx |
|---|---|---|---|---|
| Botões de resposta | button | texto, imagem, vídeo, documento | sim | 1024 |
| Menus de lista | list | somente texto | sim | 4096 |
| Botões de link | cta_url | texto, imagem, vídeo, documento | sim | 1024 |
| Carrosséis de mídia | carousel | nenhum na mensagem; imagem ou vídeo por card | não | 1024 mensagem, 160 por card |
| Solicitações de localização | location_request_message | nenhum | não | 1024 |
| Solicitações de dados de contato | request_contact_info | nenhum | não | 1024 |
Todos os tipos são de formato livre: entregues apenas dentro de uma janela de atendimento ao cliente aberta, e nunca revisados pela Meta como um template é.
Mensagens interativas são conteúdo de formato livre, então a regra da janela de atendimento ao cliente se aplica: veja a janela de atendimento ao cliente para entender o que isso significa e o que uma janela fechada retorna.
Todo envio interativo também exige from, um número que o seu espaço de trabalho possui. Os números gerenciados do Bird não suportam isso, então um envio interativo precisa de um número próprio conectado primeiro.
O campo de conteúdo interativo
interactive é um dos campos de conteúdo mutuamente exclusivos em POST /v1/whatsapp/messages, ao lado de template, text, image e os demais: exatamente um pode estar presente em um envio. Dentro de interactive, type indica qual das seis variantes é, e o campo próprio dessa variante carrega o restante (buttons, list, cta_url ou cards). O schema bloqueia o campo de qualquer outra variante, então misturar duas variantes em um envio falha na validação antes de chegar a um handler.
Para o envelope de solicitação, o modelo de resposta 202 e retentativas seguras, veja Enviando mensagens do WhatsApp em vez de esta página repeti-los.
Aqui está uma mensagem interativa mínima: dois botões WhatsApp em um envio de botões de resposta, um idioma por vez.
const msg = await bird.whatsapp.send({
to: "+15551234567",
from: "+13124495648",
interactive: {
type: "button",
body_text: "Your gardening workshop is scheduled for 9am tomorrow.",
buttons: [
{ type: "quick_reply", quick_reply: { slug: "change-booking", text: "Change" } },
{ type: "quick_reply", quick_reply: { slug: "cancel-booking", text: "Cancel" } },
],
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+15551234567",
from_="+13124495648",
interactive={
"type": "button",
"body_text": "Your gardening workshop is scheduled for 9am tomorrow.",
"buttons": [
{"type": "quick_reply", "quick_reply": {"slug": "change-booking", "text": "Change"}},
{"type": "quick_reply", "quick_reply": {"slug": "cancel-booking", "text": "Cancel"}},
],
},
)
print(msg.id, msg.status)package main
import (
"context"
"fmt"
"log"
"os"
bird "github.com/messagebird/bird-sdk-go"
"github.com/messagebird/bird-sdk-go/option"
)
func main() {
client, err := bird.NewClient(option.WithAPIKey(os.Getenv("BIRD_API_KEY")))
if err != nil {
log.Fatal(err)
}
msg, err := client.Whatsapp.Send(context.Background(), bird.WhatsappSendParams{
To: "+15551234567",
From: "+13124495648",
Interactive: &bird.WhatsAppInteractiveSend{
Type: "button",
BodyText: "Your gardening workshop is scheduled for 9am tomorrow.",
Buttons: &[]bird.WhatsAppInteractiveButtonSend{
{Type: "quick_reply", QuickReply: &bird.WhatsAppInteractiveQuickReplyButtonSend{Slug: "change-booking", Text: "Change"}},
{Type: "quick_reply", QuickReply: &bird.WhatsAppInteractiveQuickReplyButtonSend{Slug: "cancel-booking", Text: "Cancel"}},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)
}$interactive = (new WhatsAppMessageSendRequestInteractive())
->setType('button')
->setBodyText('Your gardening workshop is scheduled for 9am tomorrow.')
->setButtons([
(new WhatsAppInteractiveButtonSend())
->setType('quick_reply')
->setQuickReply((new WhatsAppInteractiveButtonSendQuickReply())->setSlug('change-booking')->setText('Change')),
(new WhatsAppInteractiveButtonSend())
->setType('quick_reply')
->setQuickReply((new WhatsAppInteractiveButtonSendQuickReply())->setSlug('cancel-booking')->setText('Cancel')),
]);
$message = $bird->whatsapp->send(
to: '+15551234567',
from: '+13124495648',
interactive: $interactive,
);
echo $message->getId(), ' ', $message->getStatus();bird whatsapp send \
--from +13124495648 \
--interactive '{"body_text":"Your gardening workshop is scheduled for 9am tomorrow.","buttons":[{"quick_reply":{"slug":"change-booking","text":"Change"},"type":"quick_reply"},{"quick_reply":{"slug":"cancel-booking","text":"Cancel"},"type":"quick_reply"}],"type":"button"}' \
--to +15551234567{
"name": "whatsapp_send",
"arguments": {
"from": "+13124495648",
"interactive": {
"body_text": "Your gardening workshop is scheduled for 9am tomorrow.",
"buttons": [
{
"quick_reply": {
"slug": "change-booking",
"text": "Change"
},
"type": "quick_reply"
},
{
"quick_reply": {
"slug": "cancel-booking",
"text": "Cancel"
},
"type": "quick_reply"
}
],
"type": "button"
},
"to": "+15551234567"
}
}curl -X POST "https://{region}.platform.bird.com/v1/whatsapp/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "+15551234567",
"from": "+13124495648",
"interactive": {
"type": "button",
"body_text": "Your gardening workshop is scheduled for 9am tomorrow.",
"buttons": [
{ "type": "quick_reply", "quick_reply": { "slug": "change-booking", "text": "Change" } },
{ "type": "quick_reply", "quick_reply": { "slug": "cancel-booking", "text": "Cancel" } }
]
}
}'Botões
Quatro dos seis tipos posicionam um botão, e todos usam o mesmo formato: um objeto discriminado cujo type é quick_reply ou cta_url, cada um carregando seu próprio campo aninhado com o mesmo nome. Um botão quick_reply carrega slug e text; um botão cta_url carrega text e url. Quais tipos aceitam qual formato de botão:
- Botões de resposta enviam apenas botões quick_reply, de 1 a 3.
- Botões de link enviam exatamente um botão cta_url.
- Carrosséis de mídia colocam botões em cada card: um botão cta_url ou até três botões quick_reply, e todos os cards do carrossel devem concordar.
- Menus de lista usam linhas dentro de seções em vez deste objeto de botão, cobertos na sua própria página.
O slug de um botão quick_reply é o seu próprio identificador para aquele botão. Ele nunca é exibido ao destinatário, apenas o rótulo text é, e o slug é retornado literalmente na resposta. Esse ciclo é o que torna uma resposta correlacionável ao botão que a produziu, por isso vale dizer isso uma vez, aqui, em vez de em cada página específica.
Lendo uma resposta
Pressionar um botão ou escolher uma linha de menu envia sua própria mensagem de entrada, contendo um objeto interactive_reply. interactive_reply.type é button ou list; seja qual for, o objeto aninhado carrega o slug e o text que você declarou, o rótulo tocado que o destinatário realmente viu. Os dois tipos de solicitação, solicitações de localização e solicitações de dados de contato, respondem de forma diferente: a resposta a uma solicitação de localização é uma mensagem de entrada comum de localização, e a resposta a uma solicitação de dados de contato é um cartão de contato de entrada, não um interactive_reply.
Uma resposta chega até você pela lista de mensagens e GET /v1/whatsapp/messages/{id}, da mesma forma que qualquer mensagem WhatsApp de entrada. Para agir sobre uma assim que ela chega em vez de fazer polling, assine o webhook whatsapp.received: seu payload carrega interactive_reply, então já nomeia o botão ou linha que foi tocado. Recebendo respostas interativas cobre o formato de leitura de um toque, o payload do webhook e os toques que chegam em outro campo.
Citando uma mensagem para correlacionar uma resposta
in_reply_to_message_id em um envio cita uma mensagem anterior da mesma conversa, e toda mensagem, enviada ou recebida, o retorna em uma leitura. É um campo para ambas as direções.
A correlação que isso oferece é assimétrica. Um toque em um botão WhatsApp ou linha de menu carrega o próprio context da Meta, então in_reply_to_message_id resolve para a mensagem que o ofereceu. Um cartão de contato compartilhado não carrega nenhum context, então não resolve para nada: você correlaciona a resposta de uma solicitação de dados de contato por from e timing, não por este campo.
A resolução passa por um armazenamento de contexto de mensagem, e uma falha omite o campo em vez de reportar um. Isso é indistinguível, no fio, de uma resposta que não responde a nada. Uma integração que precisa de correlação confiável não deve depender apenas deste campo: carregue seu próprio metadata no envio e faça a correspondência por ele.
A janela em que uma mensagem permanece citável é limitada a 15 dias; após isso, o envio falha com um 404 E15071, porque Bird não retém mais o id do provedor que uma citação precisa. Enviando mensagens do WhatsApp é dono do campo no lado do envio: seu comprimento, sua resolução e o formato da solicitação.
Erros
Três códigos de erro são específicos de conteúdo interativo. Cada um dispara apenas nos tipos que possuem o campo que ele verifica, então a quarta coluna indica quais tipos podem realmente alcançar cada um.
| Código | Status | O que o dispara | Se aplica a |
|---|---|---|---|
| E15055 WhatsAppInteractiveLimitExceeded | 422 | A mensagem excede um limite para seu tipo; mais de 10 linhas nas seções de uma lista. | Somente menus de lista |
| E15056 WhatsAppInteractiveDuplicateLabel | 422 | Dois botões ou linhas na mesma mensagem compartilham um rótulo. | Qualquer tipo com botões ou linhas rotulados: botões de resposta, menus de lista, carrosséis de mídia |
| E15059 WhatsAppInteractiveCarouselButtonsMismatch | 422 | Os cards de um carrossel não carregam todos os mesmos botões. | Somente carrosséis de mídia |
Todo envio interativo também pode atingir os erros que qualquer envio WhatsApp pode: uma janela de atendimento ao cliente fechada, um remetente ausente ou inválido, um destinatário inválido ou conteúdo ambíguo. Esses são compartilhados entre todos os tipos de conteúdo WhatsApp, não específicos de mensagens interativas; veja Enviando mensagens do WhatsApp para essa lista em vez de uma cópia dela aqui.
Próximos passos
- Enviando mensagens do WhatsApp: o envelope de solicitação, o modelo 202 e retentativas seguras
- Eventos do WhatsApp: acompanhe a entrega por mensagem, pela API ou webhooks
- Templates do WhatsApp: as mensagens que você ainda pode enviar quando a janela está fechada
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico. Os recursos estão em inglês.
Assista ao guiaConnecting WhatsApp to Bird: from buying a number to a live channelEntenda o conceitoWhat is the 24-hour customer service window on WhatsApp?Use a ferramentaWhatsApp message builderExplore a funcionalidadeWhatsApp
Experimente na prática e obtenha um resumo de implementação