Caroselli multimediali WhatsApp
Un carosello multimediale è un insieme da due a dieci card che il destinatario scorre affiancate, ciascuna con la propria immagine o video, il proprio testo breve e i propri pulsanti. Usalo per mostrare più elementi contemporaneamente, ad esempio una serie di prodotti, invece di inviare un messaggio per ogni elemento.
Inviare un carosello
Imposta interactive.type su carousel, con un body_text a livello di messaggio e un array cards da 2 a 10 elementi:
const msg = await bird.whatsapp.send({
to: "+16505551234",
from: "+13124495648",
interactive: {
type: "carousel",
body_text: "Here are two of our latest arrivals, each under $25:",
cards: [
{
header: { type: "image", url: "https://cdn.example.com/plants/blue-echeveria.jpeg" },
buttons: [
{
type: "cta_url",
cta_url: { text: "Buy now", url: "https://shop.example.com/blue-echeveria" },
},
],
},
{
header: { type: "image", url: "https://cdn.example.com/plants/zebra-haworthia.jpeg" },
buttons: [
{
type: "cta_url",
cta_url: { text: "Buy now", url: "https://shop.example.com/zebra-haworthia" },
},
],
},
],
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+16505551234",
from_="+13124495648",
interactive={
"type": "carousel",
"body_text": "Here are two of our latest arrivals, each under $25:",
"cards": [
{
"header": {"type": "image", "url": "https://cdn.example.com/plants/blue-echeveria.jpeg"},
"buttons": [{"type": "cta_url", "cta_url": {"text": "Buy now", "url": "https://shop.example.com/blue-echeveria"}}],
},
{
"header": {"type": "image", "url": "https://cdn.example.com/plants/zebra-haworthia.jpeg"},
"buttons": [{"type": "cta_url", "cta_url": {"text": "Buy now", "url": "https://shop.example.com/zebra-haworthia"}}],
},
],
},
)
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: "carousel",
BodyText: "Here are two of our latest arrivals, each under $25:",
Cards: &[]bird.WhatsAppInteractiveCardSend{
{
Header: bird.WhatsAppInteractiveCardHeaderSend{Type: "image", Url: "https://cdn.example.com/plants/blue-echeveria.jpeg"},
Buttons: []bird.WhatsAppInteractiveButtonSend{{Type: "cta_url", CtaUrl: &bird.WhatsAppInteractiveCtaUrlSend{Text: "Buy now", Url: "https://shop.example.com/blue-echeveria"}}},
},
{
Header: bird.WhatsAppInteractiveCardHeaderSend{Type: "image", Url: "https://cdn.example.com/plants/zebra-haworthia.jpeg"},
Buttons: []bird.WhatsAppInteractiveButtonSend{{Type: "cta_url", CtaUrl: &bird.WhatsAppInteractiveCtaUrlSend{Text: "Buy now", Url: "https://shop.example.com/zebra-haworthia"}}},
},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)
}$interactive = (new WhatsAppMessageSendRequestInteractive())
->setType('carousel')
->setBodyText('Here are two of our latest arrivals, each under $25:')
->setCards([
(new WhatsAppInteractiveCardSend())
->setHeader((new WhatsAppInteractiveCardSendHeader())->setType('image')->setUrl('https://cdn.example.com/plants/blue-echeveria.jpeg'))
->setButtons([
(new WhatsAppInteractiveButtonSend())
->setType('cta_url')
->setCtaUrl((new WhatsAppInteractiveButtonSendCtaUrl())->setText('Buy now')->setUrl('https://shop.example.com/blue-echeveria')),
]),
(new WhatsAppInteractiveCardSend())
->setHeader((new WhatsAppInteractiveCardSendHeader())->setType('image')->setUrl('https://cdn.example.com/plants/zebra-haworthia.jpeg'))
->setButtons([
(new WhatsAppInteractiveButtonSend())
->setType('cta_url')
->setCtaUrl((new WhatsAppInteractiveButtonSendCtaUrl())->setText('Buy now')->setUrl('https://shop.example.com/zebra-haworthia')),
]),
]);
$message = $bird->whatsapp->send(
to: '+16505551234',
from: '+13124495648',
interactive: $interactive,
);
echo $message->getId(), ' ', $message->getStatus();bird whatsapp send \
--from +13124495648 \
--interactive '{"body_text":"Here are two of our latest arrivals, each under $25:","cards":[{"buttons":[{"cta_url":{"text":"Buy now","url":"https://shop.example.com/blue-echeveria"},"type":"cta_url"}],"header":{"type":"image","url":"https://cdn.example.com/plants/blue-echeveria.jpeg"}},{"buttons":[{"cta_url":{"text":"Buy now","url":"https://shop.example.com/zebra-haworthia"},"type":"cta_url"}],"header":{"type":"image","url":"https://cdn.example.com/plants/zebra-haworthia.jpeg"}}],"type":"carousel"}' \
--to +16505551234{
"name": "whatsapp_send",
"arguments": {
"from": "+13124495648",
"interactive": {
"body_text": "Here are two of our latest arrivals, each under $25:",
"cards": [
{
"buttons": [
{
"cta_url": {
"text": "Buy now",
"url": "https://shop.example.com/blue-echeveria"
},
"type": "cta_url"
}
],
"header": {
"type": "image",
"url": "https://cdn.example.com/plants/blue-echeveria.jpeg"
}
},
{
"buttons": [
{
"cta_url": {
"text": "Buy now",
"url": "https://shop.example.com/zebra-haworthia"
},
"type": "cta_url"
}
],
"header": {
"type": "image",
"url": "https://cdn.example.com/plants/zebra-haworthia.jpeg"
}
}
],
"type": "carousel"
},
"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": "carousel",
"body_text": "Here are two of our latest arrivals, each under $25:",
"cards": [
{
"header": { "type": "image", "url": "https://cdn.example.com/plants/blue-echeveria.jpeg" },
"buttons": [{ "type": "cta_url", "cta_url": { "text": "Buy now", "url": "https://shop.example.com/blue-echeveria" } }]
},
{
"header": { "type": "image", "url": "https://cdn.example.com/plants/zebra-haworthia.jpeg" },
"buttons": [{ "type": "cta_url", "cta_url": { "text": "Buy now", "url": "https://shop.example.com/zebra-haworthia" } }]
}
]
}
}'from è obbligatorio su ogni messaggio di servizio: un numero di proprietà del tuo spazio di lavoro, non uno gestito da Bird. La struttura completa aggiunge il testo proprio della card, un secondo pulsante di risposta rapida e una citazione di un messaggio precedente:
Esempio di codice
{
"to": "+16505551234",
"from": "+13124495648",
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"interactive": {
"type": "carousel",
"body_text": "Here are two of our latest arrivals, each under $25:",
"cards": [
{
"header": { "type": "image", "url": "https://cdn.example.com/plants/blue-echeveria.jpeg" },
"body_text": "Blue Echeveria. Powdery blue leaves.",
"buttons": [
{ "type": "quick_reply", "quick_reply": { "slug": "buy-echeveria", "text": "Buy" } },
{ "type": "quick_reply", "quick_reply": { "slug": "info-echeveria", "text": "Details" } }
]
},
{
"header": { "type": "image", "url": "https://cdn.example.com/plants/zebra-haworthia.jpeg" },
"body_text": "Zebra Haworthia. White stripes on deep green leaves.",
"buttons": [
{ "type": "quick_reply", "quick_reply": { "slug": "buy-haworthia", "text": "Buy" } },
{ "type": "quick_reply", "quick_reply": { "slug": "info-haworthia", "text": "Details" } }
]
}
]
},
"tags": [{ "name": "category", "value": "catalog" }],
"metadata": { "order_id": "A-1" }
}in_reply_to_message_id cita un messaggio precedente nella stessa conversazione. Consulta la sezione citare un messaggio per correlare una risposta nell'hub per capire come funziona la risoluzione e cosa può mancare.
Un carosello non prevede header né footer a livello di messaggio: il body_text del messaggio è l'unico testo sopra le card. Consulta la sezione pulsanti nell'hub per la struttura condivisa dei pulsanti riutilizzata dalle card di questo tipo.
Card
Ogni card contiene il proprio header multimediale, il proprio testo breve e i propri pulsanti:
- header è obbligatorio su ogni card e può essere solo image o video: nessun testo e nessun header documento, a differenza degli altri tipi interattivi.
- body_text è facoltativo. Si trova sotto il contenuto multimediale della card, è più corto di un corpo messaggio e consente al massimo due interruzioni di riga.
- buttons è obbligatorio: un solo pulsante cta_url oppure fino a tre pulsanti quick_reply, mai una combinazione sulla stessa card.
Le card vengono visualizzate da sinistra a destra nell'ordine in cui compaiono nell'array cards. Una card non ha footer né campo indice proprio; la sua posizione nell'array è la sua posizione nel carosello.
Ogni card porta gli stessi pulsanti
Ogni card in un carosello deve avere gli stessi tipi di pulsante, lo stesso numero e lo stesso ordine. Un carosello in cui la card 1 ha un pulsante cta_url e la card 2 ne ha due quick_reply viene rifiutato, così come un carosello in cui ogni card ha due pulsanti quick_reply ma in ordine diverso.
Il motivo è come WhatsApp renderizza il messaggio: un carosello è una vista a card con un layout condiviso, non un insieme di card disposte indipendentemente. Una card con una riga di pulsanti diversa spezzerebbe quel layout condiviso, quindi WhatsApp richiede che ogni card corrisponda e Bird lo verifica prima che l'invio venga creato o addebitato. Una mancata corrispondenza restituisce E15059.
Le etichette dei pulsanti seguono una regola separata, con un ambito diverso: un'etichetta deve essere univoca all'interno di una card, non nell'intero carosello. "Buy now" su ognuna delle dieci card va bene; "Buy now" due volte sulla stessa card restituisce E15056.
Limiti
| Campo | Vincolo |
|---|---|
| cards | Da 2 a 10 elementi |
| header della card | obbligatorio su ogni card; solo image o video |
| header.url della card | obbligatorio, nessuna lunghezza massima |
| body_text della card | facoltativo, da 1 a 160 caratteri, massimo 2 interruzioni di riga |
| buttons della card | Da 1 a 3 elementi: un cta_url, oppure fino a tre quick_reply, mai misti |
| Etichetta pulsante (quick_reply.text, cta_url.text) | obbligatoria, da 1 a 20 caratteri, univoca all'interno della card |
| quick_reply.slug | obbligatorio, da 1 a 256 caratteri |
| cta_url.url | obbligatorio, da 1 a 2000 caratteri |
| body_text del messaggio | obbligatorio, da 1 a 1024 caratteri |
| Header e footer del messaggio | non consentiti su un carosello: nessun header, nessun footer_text |
Bird limita i pulsanti quick_reply a tre per card. Meta stessa non dichiara un limite numerico, ma solo che una card accetta un pulsante link oppure uno o più pulsanti di risposta, quindi questo tetto è proprio di Bird, non di WhatsApp.
Leggere la risposta
Solo un pulsante quick_reply su una card produce una risposta. Un tap su di esso arriva come messaggio in entrata a sé stante, con interactive_reply:
Esempio di codice
{
"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": "buy-echeveria",
"text": "Buy"
}
},
"created_at": "2026-08-25T09:04:11Z"
}Il slug impostato sul pulsante premuto torna esattamente su interactive_reply.button.slug, con la stessa struttura prodotta dal tap su un pulsante di risposta. Puoi vedere questa risposta tramite l'elenco dei messaggi o GET /v1/whatsapp/messages/{id}; consulta la sezione leggere una risposta nell'hub per il percorso completo.
Un pulsante cta_url su una card apre il suo link nel browser del destinatario e non invia nulla indietro, come un pulsante link autonomo.
Caroselli liberi e caroselli template
Questa pagina tratta il carosello libero che invii inline con interactive.type: "carousel", consegnabile solo all'interno di una finestra di assistenza clienti aperta e mai revisionato da Meta. Template WhatsApp ha un proprio carosello separato: un componente template creato una volta, inviato a Meta per approvazione e spedito per slug come qualsiasi altro template, anche fuori dalla finestra. I due condividono la parola "carousel" e l'intervallo da 2 a 10 card di Meta, e nient'altro: strutture wire diverse, percorsi di revisione diversi, e il numero di card di un carosello template è fissato al momento dell'approvazione del template anziché scelto per ogni invio. Se stai esplorando i template e vedi "carousel" lì, quello è il tipo template, non questa pagina.
Limiti e casi particolari
- La finestra di assistenza clienti deve essere aperta. Un carosello è un messaggio di servizio, consegnabile solo all'interno di una finestra aperta; consulta la sezione finestra di assistenza clienti nell'hub. Il controllo della finestra fallisce in modalità aperta, quindi un 202 non è prova che la finestra fosse effettivamente aperta al momento dell'invio.
- from deve essere un numero di proprietà del tuo spazio di lavoro. Ometterlo, o indicare un numero che non è un mittente connesso, viene rifiutato prima che l'invio venga creato.
- Il contenuto multimediale della card deve essere raggiungibile pubblicamente al momento dell'invio. Bird non archivia né fa da proxy per il file: WhatsApp recupera il url di ogni card direttamente, al momento dell'invio, quindi un URL firmato deve sopravvivere all'invio.
- Un URL multimediale di una card che WhatsApp non riesce a recuperare viene accettato, poi fallisce in modo asincrono, e viene comunque addebitato. La validazione della richiesta di Bird verifica solo che il url di una card sia un URI ben formato, non che WhatsApp possa raggiungerlo o che utilizzi https. Un file sovradimensionato, un 404, un host non risolvibile o un tipo di file errato tornano tutti come 202 all'accettazione, poi whatsapp.accepted poi whatsapp.sent poi whatsapp.failed, con media_rejected sul last_error del messaggio e il costo dell'invio già addebitato senza possibilità di rimborso. Testa l'URL di ogni card prima dell'invio, perché un URL non funzionante non viene rilevato fino a cose fatte.
- Ogni card deve avere gli stessi pulsanti. Consulta Ogni card porta gli stessi pulsanti sopra; questa è l'unica regola del carosello che lo schema della richiesta non può esprimere da solo, quindi viene verificata separatamente e restituisce E15059 anziché un errore di validazione generico.
- Nessun header o footer a livello di messaggio. L'unico testo sopra le card di un carosello è body_text; non c'è spazio per note a piè di pagina come negli altri tipi con footer_text.
- La risposta non contiene l'indice della card. Il tap su quick_reply di una card riporta solo {slug, text}, la stessa struttura di un tap su pulsanti di risposta, senza alcun campo che indichi da quale card proviene. Se devi sapere quale card è stata premuta, codifica la card nel slug di ogni pulsante, ad esempio buy-echeveria anziché un semplice buy.
- Un pulsante cta_url su una card non genera alcun evento in entrata. Se devi sapere che una card ha ricevuto un'interazione, usa i pulsanti quick_reply su quella card, oppure traccia il clic sul tuo URL di destinazione.
Oltre a E15059, l'unico errore interattivo specifico di un carosello è E15056 per un'etichetta di pulsante ripetuta su una card. Una citazione che non si risolve fa fallire la richiesta prima che venga creato o addebitato qualcosa: 404 E15071 quando l'id indica un messaggio non presente in questo spazio di lavoro, 422 E15072 quando indica un messaggio che non può essere citato. Per gli errori che qualsiasi invio WhatsApp può incontrare, finestra chiusa, mittente mancante o non valido, o destinatario non valido, consulta le sezioni errori e Invio di messaggi WhatsApp nell'hub.
Prossimi passi
- Messaggi interattivi WhatsApp: cosa condividono tutti e sei i tipi interattivi
- Template WhatsApp: per un carosello da inviare al di fuori della finestra di assistenza clienti
- Invio di messaggi WhatsApp: la struttura della richiesta, il modello 202 e i tentativi sicuri di riprovare
Risorse correlate
Prosegui con la documentazione, le guide e gli esempi per questo argomento. Le risorse sono in inglese.
Guarda la guidaConnecting WhatsApp to Bird: from buying a number to a live channelComprendi il concettoWhat is the 24-hour customer service window on WhatsApp?Usa lo strumentoWhatsApp message builderEsplora la funzionalitàWhatsApp
Prova l'esercitazione e ottieni un brief di implementazione