WhatsApp-Medienkarussells
Ein Medienkarussell ist eine Gruppe von zwei bis zehn Karten, die der Empfänger nebeneinander durchwischen kann – jede mit eigenem Bild oder Video, eigenem Kurztext und eigenen Buttons. Nutzen Sie es, um mehrere Elemente auf einmal zu zeigen, etwa eine Handvoll Produkte, statt pro Element eine eigene Nachricht zu senden.
Karussell senden
Setzen Sie interactive.type auf carousel, mit einem body_text auf Nachrichtenebene und einem cards-Array mit 2 bis 10 Einträgen:
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 ist bei jeder Servicenachricht erforderlich: eine Nummer, die Ihrem Workspace gehört, keine von Bird verwaltete. Die vollständige Struktur ergänzt einen eigenen Text der Karte, einen zweiten Quick-Reply-Button und ein Zitat einer früheren Nachricht:
Codebeispiel
{
"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 zitiert eine frühere Nachricht in derselben Konversation. Unter Nachricht zitieren, um eine Antwort zuzuordnen im Hub erfahren Sie, wie die Auflösung funktioniert und was sie verfehlen kann.
Ein Karussell hat keinen Header und keinen Footer auf Nachrichtenebene: body_text der Nachricht ist der einzige Text oberhalb der Karten. Im Abschnitt Buttons des Hubs finden Sie die gemeinsame Button-Struktur, die die Karten dieses Typs wiederverwenden.
Karten
Jede Karte hat einen eigenen Medien-Header, einen eigenen Kurztext und eigene Buttons:
- header ist auf jeder Karte erforderlich und ausschließlich image oder video: kein Text- und kein Dokument-Header, anders als bei den übrigen interaktiven Typen.
- body_text ist optional. Er steht unterhalb des Medienbereichs der Karte, ist kürzer als ein Nachrichtentext begrenzt und erlaubt maximal zwei Zeilenumbrüche.
- buttons ist erforderlich: entweder ein cta_url-Button oder bis zu drei quick_reply-Buttons, nie gemischt auf derselben Karte.
Karten werden von links nach rechts in der Reihenfolge gerendert, in der sie im cards-Array erscheinen. Eine Karte hat keinen Footer und kein eigenes Index-Feld; ihre Position im Array ist ihre Position im Karussell.
Jede Karte hat dieselben Buttons
Jede Karte in einem Karussell muss dieselben Button-Typen, dieselbe Anzahl davon und in derselben Reihenfolge haben. Ein Karussell, in dem Karte 1 einen cta_url-Button und Karte 2 zwei quick_reply-Buttons hat, wird abgelehnt – ebenso ein Karussell, in dem jede Karte zwei quick_reply-Buttons hat, aber in unterschiedlicher Reihenfolge.
Der Grund liegt darin, wie WhatsApp die Nachricht rendert: Ein Karussell ist eine einzelne Kartenansicht mit gemeinsamem Layout, kein Satz unabhängig gestalteter Karten. Eine Karte mit einer anderen Button-Zeile würde dieses gemeinsame Layout brechen, daher verlangt WhatsApp, dass jede Karte übereinstimmt, und Bird prüft das, bevor der Versand erstellt oder berechnet wird. Bei einer Abweichung wird E15059 zurückgegeben.
Button-Labels unterliegen einer eigenen Regel mit anderem Geltungsbereich: Ein Label muss innerhalb einer Karte eindeutig sein, nicht über das gesamte Karussell hinweg. "Buy now" auf jeder der zehn Karten ist zulässig; "Buy now" zweimal auf derselben Karte gibt E15056 zurück.
Limits
| Feld | Grenzwert |
|---|---|
| cards | 2 bis 10 Einträge |
| Karten-header | auf jeder Karte erforderlich; nur image oder video |
| Karten-header.url | erforderlich, keine Maximallänge |
| Karten-body_text | optional, 1 bis 160 Zeichen, maximal 2 Zeilenumbrüche |
| Karten-buttons | 1 bis 3 Einträge: ein cta_url oder bis zu drei quick_reply, nie gemischt |
| Button-Label (quick_reply.text, cta_url.text) | erforderlich, 1 bis 20 Zeichen, eindeutig innerhalb der Karte |
| quick_reply.slug | erforderlich, 1 bis 256 Zeichen |
| cta_url.url | erforderlich, 1 bis 2.000 Zeichen |
| Nachrichten-body_text | erforderlich, 1 bis 1.024 Zeichen |
| Nachrichten-Header, Footer | bei einem Karussell nicht erlaubt: kein header, kein footer_text |
Bird begrenzt quick_reply-Buttons auf drei pro Karte. Meta selbst nennt kein numerisches Limit, sondern nur, dass eine Karte entweder einen Link-Button oder einen oder mehrere Reply-Buttons akzeptiert. Diese Obergrenze stammt also von Bird, nicht von WhatsApp.
Antwort auslesen
Nur ein quick_reply-Karten-Button erzeugt eine Antwort. Ein Tippen darauf kommt als eigene eingehende Nachricht an und enthält interactive_reply:
Codebeispiel
{
"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"
}Der slug, den Sie auf dem getippten Button gesetzt haben, kommt wortgetreu auf interactive_reply.button.slug zurück – dieselbe Struktur, die auch ein Reply-Buttons-Tippen erzeugt. Sie sehen diese Antwort über die Nachrichtenliste oder GET /v1/whatsapp/messages/{id}; unter Antwort auslesen im Hub finden Sie den vollständigen Ablauf.
Ein cta_url-Button auf einer Karte öffnet seinen Link im Browser des Empfängers und sendet nichts zurück – genau wie ein einzelner Link-Button.
Freitext-Karussells und Template-Karussells
Diese Seite behandelt das Freitext-Karussell, das Sie inline mit interactive.type: "carousel" senden. Es ist nur innerhalb eines offenen Kundenservice-Fensters zustellbar und wird nie von Meta geprüft. WhatsApp-Templates haben ein eigenes, separates Karussell: eine Template-Komponente, die einmal erstellt, bei Meta zur Genehmigung eingereicht und per Slug wie jedes andere Template gesendet wird – auch außerhalb des Fensters. Beide teilen das Wort "carousel" und Metas Kartenbereich von 2 bis 10, sonst nichts: unterschiedliche Wire-Strukturen, unterschiedliche Prüfpfade, und die Kartenanzahl eines Template-Karussells wird bei der Genehmigung des Templates festgelegt statt pro Versand gewählt. Wenn Sie in Templates "carousel" sehen, ist das der Template-Typ, nicht diese Seite.
Limits und Sonderfälle
- Das Kundenservice-Fenster muss geöffnet sein. Ein Karussell ist eine Servicenachricht und nur innerhalb eines offenen Fensters zustellbar; siehe Kundenservice-Fenster im Hub. Die Fensterprüfung schlägt offen fehl, ein 202 ist also kein Beweis dafür, dass das Fenster beim Versand tatsächlich geöffnet war.
- from muss eine Nummer sein, die Ihrem Workspace gehört. Wird sie weggelassen oder eine Nummer angegeben, die kein verbundener Absender ist, wird der Versand abgelehnt, bevor er erstellt wird.
- Kartenmedien müssen zum Versandzeitpunkt öffentlich erreichbar sein. Bird speichert oder proxyt die Datei nicht: WhatsApp ruft die url jeder Karte selbst zum Sendezeitpunkt ab, daher muss eine signierte URL den Versand überdauern.
- Eine Kartenmedien-URL, die WhatsApp nicht abrufen kann, wird akzeptiert, schlägt dann asynchron fehl und wird trotzdem berechnet. Die Request-Validierung von Bird prüft nur, ob die url einer Karte eine wohlgeformte URI ist, nicht ob WhatsApp sie erreichen kann oder ob sie https verwendet. Eine zu große Datei, ein 404, ein nicht auflösbarer Host oder ein falscher Dateityp kommen als 202 bei der Annahme zurück, dann whatsapp.accepted, dann whatsapp.sent, dann whatsapp.failed, mit media_rejected auf dem last_error der Nachricht, und die Kosten des Versands sind bereits ohne Erstattungspfad abgerechnet. Testen Sie die URL jeder Karte vor dem Senden, da eine fehlerhafte erst nachträglich erkannt wird.
- Jede Karte muss dieselben Buttons haben. Siehe Jede Karte hat dieselben Buttons oben; dies ist die einzige Karussell-Regel, die das Request-Schema nicht allein ausdrücken kann, daher wird sie separat geprüft und gibt E15059 statt eines generischen Validierungsfehlers zurück.
- Kein Header oder Footer auf Nachrichtenebene. Der einzige Text oberhalb der Karten eines Karussells ist body_text; es gibt keinen Platz für Kleingedrucktes, wie es die anderen Typen über footer_text nutzen.
- Die Antwort enthält keinen Kartenindex. Das Tippen auf quick_reply einer Karte meldet nur {slug, text} zurück – dieselbe Struktur wie bei einem Reply-Buttons-Tippen, ohne ein Feld, das die Karte benennt. Wenn Sie wissen müssen, welche Karte getippt wurde, codieren Sie die Karte in der slug jedes Buttons, z. B. buy-echeveria statt einem bloßen buy.
- Ein cta_url-Karten-Button erzeugt kein eingehendes Ereignis. Wenn Sie wissen müssen, ob mit einer Karte interagiert wurde, verwenden Sie stattdessen quick_reply-Buttons auf dieser Karte oder tracken Sie den Klick über Ihre eigene Ziel-URL.
Neben E15059 ist der einzige interaktive Fehler, der spezifisch für ein Karussell ist, E15056 für ein doppeltes Button-Label auf einer Karte. Ein Zitat, das nicht aufgelöst werden kann, lässt den Request fehlschlagen, bevor etwas erstellt oder berechnet wird: 404 E15071, wenn die ID keine Nachricht dieses Workspace benennt, 422 E15072, wenn sie eine benennt, die nicht zitiert werden kann. Für Fehler, die jeder WhatsApp-Versand auslösen kann – geschlossenes Fenster, fehlender oder ungültiger Absender oder ungültiger Empfänger – siehe Fehler und WhatsApp-Nachrichten senden im Hub.
Nächste Schritte
- Interaktive WhatsApp-Nachrichten: was alle sechs interaktiven Typen gemeinsam haben
- WhatsApp-Templates: für ein Karussell, das außerhalb des Kundenservice-Fensters gesendet wird
- WhatsApp-Nachrichten senden: der Request-Envelope, das 202-Modell und sicheres erneutes Versuchen
Verwandte Ressourcen
Weiter mit der Dokumentation, Anleitungen und Beispielen zu diesem Thema. Die Ressourcen sind auf Englisch.
Anleitung ansehenConnecting WhatsApp to Bird: from buying a number to a live channelDas Konzept verstehenWhat is the 24-hour customer service window on WhatsApp?Das Tool verwendenWhatsApp message builderDie Funktion erkundenWhatsApp
Übung ausprobieren und ein Implementierungs-Briefing erhalten