Sign inGet started

WhatsApp-mediacarousels

Een mediacarousel is een reeks van twee tot tien kaarten waar de ontvanger naast elkaar doorheen veegt, elk met een eigen afbeelding of video, een eigen korte tekst en eigen knoppen. Gebruik het om meerdere items tegelijk te tonen, zoals een handvol producten, in plaats van één bericht per item te versturen.
Stel interactive.type in op carousel, met een body_text op berichtniveau en een cards-array van 2 tot 10 items:
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);
from is vereist bij elk servicebericht: een nummer dat je werkruimte bezit, niet een door Bird beheerd nummer. De volledige structuur voegt de eigen tekst van een kaart, een tweede quick-reply-knop en een citaat van een eerder bericht toe:
Codevoorbeeld
{
  "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 citeert een eerder bericht in hetzelfde gesprek. Zie in de hub een bericht citeren om een antwoord te correleren voor hoe de resolutie werkt en wat het kan missen.
Een carousel heeft geen header en geen footer op berichtniveau: de body_text van het bericht is de enige tekst boven de kaarten. Zie de sectie knoppen in de hub voor de gedeelde knopstructuur die de kaarten van dit type hergebruiken.

Kaarten

Elke kaart heeft een eigen mediaheader, een eigen korte tekst en eigen knoppen:
  • header is vereist op elke kaart, en het is alleen image of video: geen tekst en geen documentheader, in tegenstelling tot de andere interactieve typen.
  • body_text is optioneel. Het staat onder de media van de kaart, is korter dan een berichttekst en staat maximaal twee regeleinden toe.
  • buttons is vereist: ofwel één cta_url-knop, ofwel maximaal drie quick_reply-knoppen, nooit een mix op dezelfde kaart.
Kaarten worden van links naar rechts weergegeven in de volgorde waarin ze in de cards-array staan. Een kaart heeft geen footer en geen eigen indexveld; de positie in de array is de positie in de carousel.

Elke kaart heeft dezelfde knoppen

Elke kaart in een carousel moet dezelfde knoptypen, hetzelfde aantal en dezelfde volgorde hebben. Een carousel waarbij kaart 1 één cta_url-knop heeft en kaart 2 twee quick_reply-knoppen, wordt geweigerd. Hetzelfde geldt voor een carousel waarbij elke kaart twee quick_reply-knoppen heeft maar in een andere volgorde.
De reden is hoe WhatsApp het bericht rendert: een carousel is één kaartweergave met een gedeelde lay-out, niet een set onafhankelijk opgemaakte kaarten. Een kaart met een andere knoprij zou die gedeelde lay-out breken, dus WhatsApp vereist dat elke kaart overeenkomt en Bird controleert dit voordat de verzending wordt aangemaakt of in rekening gebracht. Een mismatch retourneert E15059.
Knoplabels zijn een aparte regel, en die regel heeft een ander bereik: een label moet uniek zijn binnen een kaart, niet binnen de hele carousel. "Buy now" op elk van de tien kaarten is prima; "Buy now" twee keer op dezelfde kaart retourneert E15056.

Limieten

VeldGrens
cards2 tot 10 items
Kaart headervereist op elke kaart; alleen image of video
Kaart header.urlvereist, geen maximumlengte
Kaart body_textoptioneel, 1 tot 160 tekens, maximaal 2 regeleinden
Kaart buttons1 tot 3 items: één cta_url, of maximaal drie quick_reply, nooit gemengd
Knoplabel (quick_reply.text, cta_url.text)vereist, 1 tot 20 tekens, uniek binnen de kaart
quick_reply.slugvereist, 1 tot 256 tekens
cta_url.urlvereist, 1 tot 2000 tekens
Bericht body_textvereist, 1 tot 1024 tekens
Berichtheader, footerniet toegestaan op een carousel: geen header, geen footer_text
Bird beperkt quick_reply-knoppen tot drie per kaart. Meta zelf noemt geen numerieke limiet, alleen dat een kaart ofwel één linkknop ofwel één of meer antwoordknoppen heeft, dus dit plafond is van Bird, niet van WhatsApp.

Het antwoord lezen

Alleen een quick_reply-kaartknop levert een antwoord op. Een tik erop komt binnen als een eigen inbound bericht, met interactive_reply:
Codevoorbeeld
{
  "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"
}
De slug die je op de aangetikte knop hebt ingesteld, komt letterlijk terug op interactive_reply.button.slug, dezelfde structuur als bij een tik op reply-buttons. Je ziet dit antwoord via de berichtenlijst of GET /v1/whatsapp/messages/{id}; zie in de hub een antwoord lezen voor het volledige pad.
Een cta_url-knop op een kaart opent de link in de browser van de ontvanger en stuurt niets terug, net als een losse linkknop.

Vrije-vormcarousels en templatecarousels

Deze pagina behandelt de vrije-vormcarousel die je inline verstuurt met interactive.type: "carousel", alleen leverbaar binnen een open klantenservicevenster en nooit beoordeeld door Meta. WhatsApp-templates heeft een eigen, aparte carousel: een templatecomponent die je eenmalig opstelt, ter goedkeuring bij Meta indient en per slug verstuurt zoals elke andere template, ook buiten het venster. De twee delen het woord "carousel" en Meta's bereik van 2 tot 10 kaarten, en verder niets: verschillende wire-structuren, verschillende beoordelingspaden, en het aantal kaarten van een templatecarousel ligt vast bij de goedkeuring van de template in plaats van per verzending te worden gekozen. Als je door templates bladert en daar "carousel" ziet, is dat het templatetype, niet deze pagina.

Limieten en randgevallen

  • Het klantenservicevenster moet open zijn. Een carousel is een servicebericht, alleen leverbaar binnen een open venster; zie in de hub klantenservicevenster. De venstercontrole faalt open, dus een 202 is geen bewijs dat het venster daadwerkelijk open was toen de verzending uitgaat.
  • from moet een nummer zijn dat je werkruimte bezit. Weglaten, of een nummer opgeven dat geen verbonden afzender is, wordt geweigerd voordat de verzending wordt aangemaakt.
  • Kaartmedia moet publiek bereikbaar zijn wanneer de verzending wordt verstuurd. Bird slaat het bestand niet op en proxyt het niet: WhatsApp haalt de url van elke kaart zelf op, op het moment van verzenden, dus een ondertekende URL moet langer geldig zijn dan de verzending.
  • Een kaartmedia-URL die WhatsApp niet kan ophalen wordt geaccepteerd, faalt vervolgens asynchroon en wordt alsnog in rekening gebracht. De requestvalidatie van Bird controleert alleen of de url van een kaart een goed gevormde URI is, niet of WhatsApp hem kan bereiken of dat hij https gebruikt. Een te groot bestand, een 404, een niet-oplosbare host of het verkeerde bestandstype komen allemaal terug als een 202 bij acceptatie, dan whatsapp.accepted dan whatsapp.sent dan whatsapp.failed, met media_rejected op de last_error van het bericht en de kosten van de verzending al in rekening gebracht zonder restitutiepad. Test de URL van elke kaart voordat je verstuurt, want een defecte URL wordt pas achteraf opgemerkt.
  • Elke kaart moet dezelfde knoppen hebben. Zie Elke kaart heeft dezelfde knoppen hierboven; dit is de enige carouselregel die het requestschema niet op zichzelf kan uitdrukken, dus wordt het apart gecontroleerd en retourneert E15059 in plaats van een generieke validatiefout.
  • Geen header of footer op berichtniveau. De enige tekst boven de kaarten van een carousel is body_text; er is geen plek voor kleine lettertjes zoals de andere typen footer_text gebruiken.
  • Het antwoord bevat geen kaartindex. Een tik op quick_reply van een kaart rapporteert alleen {slug, text}, dezelfde structuur als een tik op reply-buttons, zonder een veld dat aangeeft van welke kaart het afkomstig is. Als je wilt weten op welke kaart is getikt, codeer je de kaart in de slug van elke knop, zoals buy-echeveria in plaats van een kale buy.
  • Een cta_url-kaartknop genereert geen inbound event. Als je wilt weten of er interactie met een kaart was, gebruik dan quick_reply-knoppen op die kaart, of volg de klik op je eigen bestemmings-URL.
Naast E15059 is de enige interactieve fout specifiek voor een carousel E15056 voor een herhaald knoplabel op één kaart. Een citaat dat niet kan worden opgelost laat het request falen voordat er iets wordt aangemaakt of in rekening gebracht: 404 E15071 wanneer het id geen bericht noemt dat deze werkruimte bezit, 422 E15072 wanneer het er een noemt die niet kan worden geciteerd. Zie voor de fouten die elke WhatsApp-verzending kan tegenkomen, zoals een gesloten venster, een ontbrekende of ongeldige afzender, of een ongeldige ontvanger, de fouten en WhatsApp-berichten versturen in de hub.

Volgende stappen