WhatsApp-lijstmenu's
Een lijstmenu verschijnt als een tikbare knop onder een WhatsApp-bericht en klapt open in rijen gegroepeerd in secties, zodat de ontvanger er één kiest uit een langere set opties in plaats van vrije tekst te typen. Gebruik het zodra de keuzelijst langer is dan drie; voor drie of minder zijn antwoordknoppen de eenvoudigere vorm.
- Track my orderFind your latest delivery update
- Collect my orderCheck your collection details
- Talk to our teamGet help from customer care
Een lijstmenu versturen
Stel interactive.type in op list, met een body_text en een list-object dat button_text en minstens één sectie bevat:
const msg = await bird.whatsapp.send({
to: "+16505551234",
from: "+13124495648",
interactive: {
type: "list",
body_text: "Which shipping option do you prefer?",
list: {
button_text: "Shipping options",
sections: [
{
title: "As soon as possible",
rows: [{ slug: "priority_express", text: "Priority Mail Express" }],
},
],
},
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+16505551234",
from_="+13124495648",
interactive={
"type": "list",
"body_text": "Which shipping option do you prefer?",
"list": {
"button_text": "Shipping options",
"sections": [
{
"title": "As soon as possible",
"rows": [{"slug": "priority_express", "text": "Priority Mail Express"}],
}
],
},
},
)
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: "list",
BodyText: "Which shipping option do you prefer?",
List: &bird.WhatsAppInteractiveListSend{
ButtonText: "Shipping options",
Sections: []bird.WhatsAppInteractiveListSectionSend{
{
Title: "As soon as possible",
Rows: []bird.WhatsAppInteractiveListRowSend{
{Slug: "priority_express", Text: "Priority Mail Express"},
},
},
},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)
}$interactive = (new WhatsAppMessageSendRequestInteractive())
->setType('list')
->setBodyText('Which shipping option do you prefer?')
->setList(
(new WhatsAppInteractiveSendList())
->setButtonText('Shipping options')
->setSections([
(new WhatsAppInteractiveListSectionSend())
->setTitle('As soon as possible')
->setRows([
(new WhatsAppInteractiveListRowSend())
->setSlug('priority_express')
->setText('Priority Mail Express'),
]),
]),
);
$message = $bird->whatsapp->send(
to: '+16505551234',
from: '+13124495648',
interactive: $interactive,
);
echo $message->getId(), ' ', $message->getStatus();bird whatsapp send \
--from +13124495648 \
--interactive '{"body_text":"Which shipping option do you prefer?","list":{"button_text":"Shipping options","sections":[{"rows":[{"slug":"priority_express","text":"Priority Mail Express"}],"title":"As soon as possible"}]},"type":"list"}' \
--to +16505551234curl -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": "list",
"body_text": "Which shipping option do you prefer?",
"list": {
"button_text": "Shipping options",
"sections": [
{
"title": "As soon as possible",
"rows": [{ "slug": "priority_express", "text": "Priority Mail Express" }]
}
]
}
}
}'from is vereist bij elk servicebericht: een nummer dat je werkruimte bezit, geen door Bird beheerd nummer. De volledige structuur voegt een optionele tekstheader, een footer, een citaat van een eerder bericht, een tweede sectie en een rijbeschrijving toe:
{
"to": "+16505551234",
"from": "+13124495648",
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"interactive": {
"type": "list",
"header": { "type": "text", "text": "Choose a shipping option" },
"body_text": "Which shipping option do you prefer?",
"footer_text": "Lucky Shrub",
"list": {
"button_text": "Shipping options",
"sections": [
{
"title": "As soon as possible",
"rows": [
{
"slug": "priority_express",
"text": "Priority Mail Express",
"description": "Next day to 2 days"
}
]
},
{
"title": "I can wait a bit",
"rows": [
{
"slug": "ground_advantage",
"text": "Ground Advantage",
"description": "2 to 5 days"
}
]
}
]
}
},
"tags": [{ "name": "flow", "value": "shipping-choice" }],
"metadata": { "order_id": "A1B2C3" }
}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 resolutie werkt en wat het kan missen.
Een lijstmenu gebruikt list.sections in plaats van het gedeelde knopobject; zie de sectie knoppen in de hub voor hoe de andere typen die vorm wel gebruiken.
Secties en rijen
list.button_text is het label op de knop die het menu opent, maximaal 20 tekens. Tikken opent het menu: elke sectie wordt weergegeven onder zijn eigen title, en elke rij in een sectie toont zijn text-label met het optionele description eronder, in kleiner lettertype. De title van een sectie is vereist, ook als het menu maar één sectie heeft, omdat WhatsApp deze altijd boven de rijen van die sectie toont.
De slug van een rij is je eigen identifier voor die rij, nooit zichtbaar voor de ontvanger. Alleen text wordt in de chat weergegeven, en de slug wordt letterlijk teruggegeven in het antwoord, dezelfde round trip die de hub beschrijft voor knoppen. Er is geen validatie op de tekens in slug: zet er in wat je eigen routering nodig heeft.
Limieten
| Veld | Grens |
|---|---|
| Secties per bericht | 1 tot 10 |
| Rijen per sectie | 1 tot 10 |
| Rijen over alle secties | 10, totaal |
Sectie-title | vereist, 1 tot 24 tekens |
Rij-slug | vereist, 1 tot 200 tekens, alle tekens toegestaan |
Rij-text (label) | vereist, 1 tot 24 tekens, uniek over het hele bericht |
Rij-description | optioneel, maximaal 72 tekens |
list.button_text | vereist, 1 tot 20 tekens |
body_text | vereist, 1 tot 4096 tekens |
footer_text | optioneel, maximaal 60 tekens |
header.text | 1 tot 60 tekens |
Twee van deze limieten zijn makkelijk verkeerd te lezen.
Het rijmaximum is tien over alle secties, niet tien per sectie. Elke sectie staat onafhankelijk maximaal 10 rijen toe, maar het bericht als geheel stopt bij 10 rijen totaal. Drie secties van elk 4 rijen slagen voor elke per-sectiecontrole en overschrijden toch het totaal, dat apart van het per-sectieaantal wordt afgedwongen en E15055 retourneert met een bericht dat vermeldt hoeveel rijen de verzending daadwerkelijk aanbood.
body_text is het enige veld dat de volledige 4096 tekens behoudt. Elk ander interactief type beperkt de body tot 1024; een lijstmenu is het enige dat WhatsApp toestaat de volledige lengte te gebruiken, dus kies hiervoor wanneer de keuze meer context nodig heeft dan een kort bericht.
De keuze uitlezen
Een rijtik komt binnen als een eigen inkomend bericht, met interactive_reply:
{
"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": "list",
"list": {
"slug": "priority_express",
"text": "Priority Mail Express",
"description": "Next day to 2 days"
}
},
"created_at": "2026-08-25T09:04:11Z"
}De slug die je op de gekozen rij hebt ingesteld, komt letterlijk terug, zodat je er direct op kunt vertakken. description is alleen aanwezig als de rij er een bevatte. Je ziet dit antwoord via de berichtenlijst of GET /v1/whatsapp/messages/{id}; zie in de hub een antwoord uitlezen voor het volledige pad.
Limieten en randgevallen
- Het klantenservicevenster moet open zijn. Een lijstmenu is een servicebericht, alleen bezorgbaar binnen een open venster; zie in de hub klantenservicevenster. De venstercontrole faalt open, dus een
202is geen bewijs dat het venster daadwerkelijk open was op het moment van verzenden. frommoet een nummer zijn dat je werkruimte bezit. Weglaten, of een nummer opgeven dat geen gekoppelde afzender is, wordt geweigerd voordat de verzending wordt aangemaakt.- De header is alleen tekst, en een mediaheader mislukt als een generieke fout. Een lijst is het enige interactieve type waarvan de header geen afbeelding, video of document kan bevatten. Toch een mediaheader meesturen levert geen WhatsApp-specifieke foutcode op: het faalt op algemene requestvalidatie, dus een developer die debugt op foutcode ziet alleen dat de request validatie niet doorstond en moet de details lezen om de header te vinden.
- Het sectie-overschrijdende rijmaximum is de valkuil. Per-sectielimieten en het berichtbrede totaal hebben beide een maximum van 10, dus ze lijken tweemaal hetzelfde getal. Ze zijn niet optelbaar: een menu dat elke per-sectiecontrole doorstaat, kan het totaal alsnog overschrijden, en alleen het totaal wordt afgedwongen.
- Rijlabels moeten uniek zijn over het hele bericht, niet alleen binnen een sectie. Twee rijen met hetzelfde
text-label, zelfs in verschillende secties, worden geweigerd met E15056. Dit is een eigen regel van Bird, niet een die Meta vermeldt: het antwoord noemt het getikte label, dus een duplicaat zou het antwoord ambigu maken, en verschillendeslug-waarden eronder lossen dat niet op. - Een Meta-side afwijzing buiten de eigen controles van Bird is vaag en kan laat binnenkomen. De controles van Bird op rijaantal en dubbele labels vangen de twee meest voorkomende fouten op voordat er iets wordt aangemaakt. Alles wat Meta daarna afwijst, verschijnt pas na de
202, op delast_errorvan het bericht, in plaats van bij de verzendaanroep zelf.
Een citaat dat niet resolveert, laat de request mislukken 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 een bericht noemt dat niet geciteerd kan worden. Voor de fouten die elke WhatsApp-verzending kan tegenkomen, een gesloten venster, een ontbrekende of ongeldige afzender, of een ongeldige ontvanger, zie in de hub fouten en WhatsApp-berichten versturen.
Volgende stappen
- Interactieve WhatsApp-berichten: wat alle zes interactieve typen gemeen hebben
- Antwoordknoppen: voor drie of minder keuzes
- WhatsApp-berichten versturen: de request-envelop, het
202-model en veilig opnieuw proberen
Gerelateerde bronnen
Ga verder met de documentatie, handleidingen en voorbeelden voor dit onderwerp.