Botões de resposta WhatsApp
Botões de resposta colocam até três opções clicáveis abaixo de uma mensagem WhatsApp, para que o destinatário responda com um toque em vez de texto livre. Use-os para uma decisão rápida, como confirmar ou cancelar uma reserva. Para mais de três opções, use menus de lista.
Enviar botões de resposta
Defina interactive.type como button, com um body_text e de um a três buttons, cada um sendo um quick_reply:
const msg = await bird.whatsapp.send({
to: "+16505551234",
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" } }],
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+16505551234",
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"}}],
},
)
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: "+16505551234",
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"}},
},
},
})
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')),
]);
$message = $bird->whatsapp->send(
to: '+16505551234',
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"}],"type":"button"}' \
--to +16505551234{
"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"
}
],
"type": "button"
},
"to": "+16505551234"
}
}curl -X POST "https://{region}.platform.bird.com/v1/whatsapp/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "+16505551234",
"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" } }
]
}
}'from é obrigatório em toda mensagem de serviço: um número que o seu espaço de trabalho possui, não um gerenciado por Bird. A estrutura completa adiciona um cabeçalho opcional, rodapé, uma citação de uma mensagem anterior e um segundo botão:
Exemplo de código
{
"to": "+16505551234",
"from": "+13124495648",
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"interactive": {
"type": "button",
"header": {
"type": "image",
"url": "https://cdn.example.com/banners/workshop.png"
},
"body_text": "Your gardening workshop is scheduled for 9am tomorrow.",
"footer_text": "Lucky Shrub, your gateway to succulents",
"buttons": [
{ "type": "quick_reply", "quick_reply": { "slug": "change-booking", "text": "Change" } },
{ "type": "quick_reply", "quick_reply": { "slug": "cancel-booking", "text": "Cancel" } }
]
},
"tags": [{ "name": "category", "value": "booking" }],
"metadata": { "order_id": "A-1" }
}in_reply_to_message_id cita uma mensagem anterior na mesma conversa. Consulte no hub citar uma mensagem para correlacionar uma resposta para saber como a resolução funciona e o que ela pode perder.
Esse tipo envia apenas botões quick_reply. Um botão cta_url pertence a um interactive.type separado e não pode aparecer junto com buttons; consulte a seção botões do hub para a estrutura compartilhada de botão.
Cabeçalhos e rodapés
O cabeçalho é opcional e tem uma de quatro formas:
Exemplo de código
"header": { "type": "text", "text": "New workshop dates" }
"header": { "type": "image", "url": "https://cdn.example.com/a.png" }
"header": { "type": "video", "url": "https://cdn.example.com/a.mp4" }
"header": { "type": "document", "url": "https://cdn.example.com/a.pdf" }Um cabeçalho de mídia (image, video ou document) carrega seu arquivo como uma URL https pública que WhatsApp busca no momento do envio, em vez de um handle de mídia enviado por upload. footer_text é opcional e adiciona uma linha abaixo dos botões.
Limites
| Campo | Limite |
|---|---|
| buttons | 1 a 3 entradas, cada uma sendo um quick_reply |
| quick_reply.slug | obrigatório, 1 a 256 caracteres |
| quick_reply.text (label) | obrigatório, 1 a 20 caracteres, único na mensagem |
| body_text | obrigatório, 1 a 1.024 caracteres |
| footer_text | opcional, 1 a 60 caracteres |
| header.text | 1 a 60 caracteres |
Bird verifica se os labels dos botões (quick_reply.text) são únicos, mas não verifica se os valores de slug são únicos, mesmo que cada slug sirva para identificar um botão. Dois botões que compartilham um slug são enviados e entregues normalmente, e suas respostas voltam indistinguíveis.
Lendo a resposta
Um toque chega como sua própria mensagem de entrada, contendo interactive_reply:
Exemplo de código
{
"id": "wam_01kyb2m4xq7whs0d8n3prv6tez",
"direction": "inbound",
"from": { "phone_number": "+16505551234" },
"to": { "phone_number": "+13124495648" },
"status": "received",
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"interactive_reply": {
"type": "button",
"button": {
"slug": "cancel-booking",
"text": "Cancel"
}
},
"created_at": "2026-08-25T09:04:11Z"
}O slug que você definiu no envio volta exatamente igual, então você pode usá-lo diretamente para ramificar a lógica sem uma tabela de consulta. Você vê essa resposta pela lista de mensagens ou por GET /v1/whatsapp/messages/{id}; consulte no hub lendo uma resposta para o caminho completo.
Limites e casos especiais
- A janela de atendimento ao cliente precisa estar aberta. Botões de resposta são uma mensagem de serviço, entregável apenas dentro de uma janela aberta; consulte no hub janela de atendimento ao cliente. A verificação da janela falha de forma permissiva, então um 202 não é prova de que a janela estava de fato aberta quando o envio é disparado.
- from deve ser um número que o seu espaço de trabalho possui. Omiti-lo, ou informar um número que não é um remetente conectado, é rejeitado antes de o envio ser criado.
- Os labels devem ser únicos, ou o envio é recusado. Dois botões com o mesmo quick_reply.text falham com 422 E15056 WhatsAppInteractiveDuplicateLabel, porque a Meta rejeitaria a duplicata depois que o envio já tivesse sido aceito e cobrado.
- O label é o que o destinatário vê; o slug nunca é. Colocar texto voltado ao usuário em slug é um no-op silencioso, já que apenas text é renderizado no chat.
- Uma URL de cabeçalho de mídia que WhatsApp não consegue buscar falha após o envio ser aceito. Bird não valida a url do cabeçalho da mesma forma que valida a URL de uma mensagem de mídia, então uma URL http:// ou que retorna um erro passa pela solicitação e depois falha de forma assíncrona, com media_rejected no last_error da mensagem.
- Enviar os próprios nomes de campo da Meta falha a solicitação. Esse tipo rejeita propriedades desconhecidas diretamente, então JSON copiado da referência Cloud API da Meta, como um objeto body ou um wrapper action.buttons, precisa ser reestruturado nos campos planos de Bird primeiro.
Uma citação que não é resolvida falha a solicitação antes de qualquer coisa ser criada ou cobrada: 404 E15071 quando o id não corresponde a nenhuma mensagem que esse espaço de trabalho possui, 422 E15072 quando corresponde a uma que não pode ser citada. Para os erros que qualquer envio WhatsApp pode encontrar, uma janela fechada, um remetente ausente ou inválido, ou um destinatário inválido, consulte no hub erros e Enviando mensagens WhatsApp.
Próximos passos
- Mensagens interativas WhatsApp: o que todos os seis tipos interativos têm em comum
- Menus de lista: para mais de três opções
- Enviando mensagens WhatsApp: a estrutura da solicitação, o modelo 202 e tentativas seguras de reenvio
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