Interactieve WhatsApp-berichten
Een interactief bericht is bodytekst plus iets waarop de ontvanger kan tikken: een WhatsApp-knop, een menu, een link, een kaart, of een verzoek om locatie of contactgegevens. Waar een templateantwoord betekent dat je vrije tekst moet parsen, geeft een WhatsApp-menu of een set WhatsApp-knoppen de ontvanger een vaste set keuzes en jou een waarde terug die je zelf hebt gedefinieerd. Deze pagina behandelt wat de zes typen delen; de eigen pagina van elk type behandelt de berichtstructuur en de eigen limieten.
De zes typen
| Type | Bird interactive.type | Header | Footer | Body max |
|---|---|---|---|---|
| Antwoordknoppen | button | tekst, afbeelding, video, document | ja | 1024 |
| Lijstmenu's | list | alleen tekst | ja | 4096 |
| Linkknoppen | cta_url | tekst, afbeelding, video, document | ja | 1024 |
| Mediacarrousels | carousel | geen op het bericht; afbeelding of video per kaart | nee | 1024 bericht, 160 per kaart |
| Locatieverzoeken | location_request_message | geen | nee | 1024 |
| Contactgegevensverzoeken | request_contact_info | geen | nee | 1024 |
Elk type is vrije vorm: alleen te versturen binnen een open klantenservicevenster, en nooit door Meta beoordeeld zoals bij een template.
Interactieve berichten zijn vrije-vorminhoud, dus de regel voor het klantenservicevenster is van toepassing: zie het klantenservicevenster voor wat dat betekent en wat een gesloten venster retourneert.
Elke interactieve verzending vereist ook from, een nummer dat je werkruimte bezit. De beheerde nummers van Bird ondersteunen dit niet, dus voor een interactieve verzending moet je eerst een eigen nummer koppelen.
Het interactieve-inhoudsveld
interactive is een van de wederzijds uitsluitende inhoudsvelden op POST /v1/whatsapp/messages, naast template, text, image, en de rest: er mag er precies één aanwezig zijn per verzending. Binnen interactive geeft type aan welke van de zes varianten het is, en het eigen veld van die variant bevat de rest (buttons, list, cta_url of cards). Het schema blokkeert het veld van elke andere variant, dus twee varianten combineren op één verzending faalt bij validatie voordat het een handler bereikt.
Voor de request-envelope, het 202-responsemodel en veilig opnieuw proberen, zie WhatsApp-berichten versturen in plaats van ze hier opnieuw uit te leggen.
Hier is een minimaal interactief bericht: twee WhatsApp-knoppen op een antwoordknoppenverzending, één taal tegelijk.
const msg = await bird.whatsapp.send({
to: "+15551234567",
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" } },
{ type: "quick_reply", quick_reply: { slug: "cancel-booking", text: "Cancel" } },
],
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+15551234567",
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"}},
{"type": "quick_reply", "quick_reply": {"slug": "cancel-booking", "text": "Cancel"}},
],
},
)
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: "+15551234567",
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"}},
{Type: "quick_reply", QuickReply: &bird.WhatsAppInteractiveQuickReplyButtonSend{Slug: "cancel-booking", Text: "Cancel"}},
},
},
})
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')),
(new WhatsAppInteractiveButtonSend())
->setType('quick_reply')
->setQuickReply((new WhatsAppInteractiveButtonSendQuickReply())->setSlug('cancel-booking')->setText('Cancel')),
]);
$message = $bird->whatsapp->send(
to: '+15551234567',
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"},{"quick_reply":{"slug":"cancel-booking","text":"Cancel"},"type":"quick_reply"}],"type":"button"}' \
--to +15551234567{
"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"
},
{
"quick_reply": {
"slug": "cancel-booking",
"text": "Cancel"
},
"type": "quick_reply"
}
],
"type": "button"
},
"to": "+15551234567"
}
}curl -X POST "https://{region}.platform.bird.com/v1/whatsapp/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "+15551234567",
"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" } },
{ "type": "quick_reply", "quick_reply": { "slug": "cancel-booking", "text": "Cancel" } }
]
}
}'Knoppen
Vier van de zes typen plaatsen een knop, en ze gebruiken allemaal dezelfde structuur: een gediscrimineerd object waarvan type de waarde quick_reply of cta_url heeft, elk met een eigen genest veld met dezelfde naam. Een quick_reply-knop bevat slug en text; een cta_url-knop bevat text en url. Welke typen welke knopvorm accepteren:
- Antwoordknoppen versturen alleen quick_reply-knoppen, 1 tot 3 stuks.
- Linkknoppen versturen precies één cta_url-knop.
- Mediacarrousels plaatsen knoppen op elke kaart: ofwel één cta_url-knop, of maximaal drie quick_reply-knoppen, en elke kaart in de carrousel moet overeenkomen.
- Lijstmenu's gebruiken rijen binnen secties in plaats van dit knopobject, behandeld op hun eigen pagina.
De slug van een quick_reply-knop is je eigen identificator voor die knop. Deze wordt nooit aan de ontvanger getoond, alleen het text-label is zichtbaar, en de slug wordt letterlijk meegestuurd in het antwoord. Die rondrit maakt een antwoord correleerbaar aan de knop die het heeft voortgebracht, dus dit is hier één keer het vermelden waard in plaats van op elke afzonderlijke pagina.
Een antwoord lezen
Het indrukken van een knop of het kiezen van een menurij verstuurt een eigen inkomend bericht met een interactive_reply-object. interactive_reply.type is button of list; in beide gevallen bevat het geneste object de slug en text die je hebt opgegeven, het aangetikte label dat de ontvanger daadwerkelijk zag. De twee verzoektypen, locatieverzoeken en contactgegevensverzoeken, antwoorden anders: het antwoord op een locatieverzoek is een gewoon inkomend locatie-bericht, en het antwoord op een contactgegevensverzoek is een inkomende contactkaart, helemaal geen interactive_reply.
Een antwoord bereikt je via de berichtenlijst en GET /v1/whatsapp/messages/{id}, op dezelfde manier als elk inkomend WhatsApp-bericht. Om op een antwoord te reageren zodra het binnenkomt in plaats van te pollen, abonneer je op de whatsapp.received-webhook: de payload bevat interactive_reply, dus die benoemt al de knop of rij waarop is getikt. Interactieve antwoorden ontvangen behandelt de leesstructuur van een tik, de webhook-payload en de tikken die op een ander veld binnenkomen.
Een bericht citeren om een antwoord te correleren
in_reply_to_message_id op een verzending citeert een eerder bericht uit hetzelfde gesprek, en elk bericht, verzonden of ontvangen, stuurt het terug bij een read. Het is één veld voor beide richtingen.
De correlatie die dit oplevert is asymmetrisch. Een tik op een WhatsApp-knop of menurij bevat Meta's eigen context, dus in_reply_to_message_id verwijst naar het bericht dat de keuze aanbood. Een gedeelde contactkaart bevat helemaal geen context, dus die verwijst naar niets: je correleert het antwoord op een contactgegevensverzoek op basis van from en timing, niet op basis van dit veld.
Resolutie verloopt via een message-context store, en een miss laat het veld weg in plaats van er een te rapporteren. Dat is op de draad niet te onderscheiden van een antwoord dat nergens op reageert. Een integratie die betrouwbare correlatie nodig heeft, moet niet alleen op dit veld vertrouwen: stuur je eigen metadata mee bij de verzending en match daarop.
Het venster waarin een bericht citeerbaar blijft is beperkt tot 15 dagen; daarna faalt de verzending met een 404 E15071, omdat Bird de provider-id die een citaat nodig heeft niet meer bevat. WhatsApp-berichten versturen beschrijft het verzendveld: de lengte, de resolutie en de requeststructuur.
Fouten
Drie foutcodes zijn specifiek voor interactieve inhoud. Elke code wordt alleen geactiveerd bij de typen die het veld hebben dat hij controleert, dus de vierde kolom vermeldt welke typen elk foutcode daadwerkelijk kunnen bereiken.
| Code | Status | Wat het veroorzaakt | Geldt voor |
|---|---|---|---|
| E15055 WhatsAppInteractiveLimitExceeded | 422 | Het bericht overschrijdt een limiet voor zijn type; meer dan 10 rijen over de secties van een lijst. | Alleen lijstmenu's |
| E15056 WhatsAppInteractiveDuplicateLabel | 422 | Twee knoppen of rijen in hetzelfde bericht delen een label. | Elk type met gelabelde knoppen of rijen: antwoordknoppen, lijstmenu's, mediacarrousels |
| E15059 WhatsAppInteractiveCarouselButtonsMismatch | 422 | De kaarten van een carrousel hebben niet allemaal dezelfde knoppen. | Alleen mediacarrousels |
Elke interactieve verzending kan ook de fouten krijgen die elke WhatsApp-verzending kan krijgen: een gesloten klantenservicevenster, een ontbrekende of ongeldige afzender, een ongeldige ontvanger of dubbelzinnige inhoud. Die worden gedeeld door elk WhatsApp-inhoudstype en zijn niet specifiek voor interactieve berichten; zie WhatsApp-berichten versturen voor die lijst in plaats van een kopie ervan hier.
Volgende stappen
- WhatsApp-berichten versturen: de request-envelope, het 202-model en veilig opnieuw proberen
- WhatsApp-events: bezorging per bericht volgen, via de API of webhooks
- WhatsApp-templates: de berichten die je nog kunt versturen als het venster gesloten is
Gerelateerde bronnen
Ga verder met de documentatie, gidsen en voorbeelden voor dit onderwerp. De bronnen zijn in het Engels.
Bekijk de gidsConnecting WhatsApp to Bird: from buying a number to a live channelBegrijp het conceptWhat is the 24-hour customer service window on WhatsApp?Gebruik de toolWhatsApp message builderOntdek de mogelijkheidWhatsApp
Probeer de oefening en ontvang een implementatieoverzicht