Botones de respuesta de WhatsApp
Los botones de respuesta colocan hasta tres opciones que se pueden pulsar debajo de un mensaje de WhatsApp, para que el destinatario responda con un toque en lugar de texto libre. Úsalos para una decisión rápida, como confirmar o cancelar una reserva. Para más de tres opciones, usa menús de lista.
Enviar botones de respuesta
Establece interactive.type en button, con un body_text y de uno a tres buttons, cada uno un 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 es obligatorio en cada mensaje de servicio: un número que tu espacio de trabajo posee, no uno gestionado por Bird. La forma completa añade un encabezado opcional, un pie, una cita de un mensaje anterior y un segundo botón:
Ejemplo 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 un mensaje anterior en la misma conversación. Consulta en el hub citar un mensaje para correlacionar una respuesta para ver cómo funciona la resolución y qué puede omitir.
Este tipo envía solo botones quick_reply. Un botón cta_url pertenece a un interactive.type separado y no puede aparecer junto a buttons; consulta la sección de botones del hub para ver la forma compartida del botón.
Encabezados y pies
El encabezado es opcional y tiene una de cuatro formas:
Ejemplo 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" }Un encabezado multimedia (image, video o document) lleva su archivo como una URL https pública que WhatsApp descarga en el momento del envío, en lugar de un handle de medio subido. footer_text es opcional y añade una línea debajo de los botones.
Límites
| Campo | Restricción |
|---|---|
| buttons | de 1 a 3 entradas, cada una un quick_reply |
| quick_reply.slug | obligatorio, de 1 a 256 caracteres |
| quick_reply.text (etiqueta) | obligatorio, de 1 a 20 caracteres, único en el mensaje |
| body_text | obligatorio, de 1 a 1024 caracteres |
| footer_text | opcional, de 1 a 60 caracteres |
| header.text | de 1 a 60 caracteres |
Bird comprueba que las etiquetas de los botones (quick_reply.text) sean únicas, pero no comprueba que los valores de slug sean únicos, aunque cada slug está pensado para identificar un solo botón. Dos botones que comparten un slug se envían y se entregan, y sus respuestas vuelven indistinguibles.
Leer la respuesta
Una pulsación llega como su propio mensaje entrante, con interactive_reply:
Ejemplo 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"
}El slug que estableciste en el envío vuelve tal cual, así que puedes bifurcar directamente con él sin una tabla de búsqueda. Ves esta respuesta a través de la lista de mensajes o GET /v1/whatsapp/messages/{id}; consulta en el hub leer una respuesta para ver esa ruta completa.
Límites y casos límite
- La ventana de atención al cliente tiene que estar abierta. Los botones de respuesta son un mensaje de servicio, entregable solo dentro de una ventana abierta; consulta en el hub ventana de atención al cliente. La comprobación de la ventana falla de forma abierta, así que un 202 no es prueba de que la ventana estuviera realmente abierta cuando el envío sale.
- from debe ser un número que tu espacio de trabajo posee. Omitirlo, o indicar un número que no sea un remitente conectado, se rechaza antes de crear el envío.
- Las etiquetas deben ser únicas o el envío se rechaza. Dos botones con el mismo quick_reply.text fallan con 422 E15056 WhatsAppInteractiveDuplicateLabel, porque Meta rechazaría el duplicado después de que el envío ya haya sido aceptado y cobrado.
- La etiqueta es lo que el destinatario ve; el slug nunca lo es. Poner texto visible para el usuario en slug no tiene efecto, ya que solo text se muestra en el chat.
- Una URL de encabezado multimedia que WhatsApp no puede descargar falla después de aceptar el envío. Bird no valida la url del encabezado como valida la URL de un mensaje multimedia, así que una URL http:// o una que devuelve un error pasa la solicitud y luego falla de forma asíncrona, con media_rejected en el last_error del mensaje.
- Enviar los propios nombres de campo de Meta hace fallar la solicitud. Este tipo rechaza propiedades desconocidas directamente, así que JSON copiado de la referencia de Cloud API de Meta, como un objeto body o un envoltorio action.buttons, necesita reestructurarse a los campos planos de Bird primero.
Una cita que no se resuelve hace fallar la solicitud antes de que se cree o cobre nada: 404 E15071 cuando el id no corresponde a ningún mensaje en este espacio de trabajo, 422 E15072 cuando corresponde a uno que no se puede citar. Para los errores que cualquier envío de WhatsApp puede generar, una ventana cerrada, un remitente faltante o inválido, o un destinatario inválido, consulta en el hub errores y Enviar mensajes de WhatsApp.
Próximos pasos
- Mensajes interactivos de WhatsApp: lo que comparten los seis tipos interactivos
- Menús de lista: para más de tres opciones
- Enviar mensajes de WhatsApp: la estructura de la solicitud, el modelo 202 y reintentos seguros
Recursos relacionados
Continúa con la documentación, guías y ejemplos sobre este tema. Los recursos están en inglés.
Ver la guíaConnecting WhatsApp to Bird: from buying a number to a live channelComprender el conceptoWhat is the 24-hour customer service window on WhatsApp?Usar la herramientaWhatsApp message builderExplorar la funcionalidadWhatsApp
Prueba el ejercicio y obtén un resumen de implementación