WhatsApp-Nachrichten senden
Diese Anleitung beschreibt den Sende-Endpunkt POST /v1/whatsapp/messages. Sie erstellen eine JSON-Payload mit einem Empfänger und genau einer Art von Inhalt: einer vorab genehmigten Vorlage oder einer Servicenachricht mit Text, einem Bild, einem Video, Audio, einem Sticker, einem Dokument, einem Standort, Kontaktkarten oder einem antippbaren Element. Bird gibt 202 Accepted mit einer Nachrichten-ID zurück und stellt asynchron zu. Welche der beiden Arten Sie senden können, hängt vom Kundenservice-Fenster ab. Jede Anfrage sendet eine Nachricht an einen Empfänger, und es gibt keinen Batch-Endpunkt.
Ein minimaler Sendevorgang
Die kleinste gültige Payload besteht aus einem to-Empfänger und einem template mit dessen slug. Fügen Sie language hinzu, wenn Sie eine bestimmte Sprache möchten. Ohne diese Angabe wird die Standardsprache der Vorlage gesendet. Füllen Sie alle Variablen, die die Vorlage deklariert, über parameters.
Der curl-Aufruf verwendet den US-Host. Wenn Ihr Schlüssel mit bk_eu1_ beginnt, rufen Sie stattdessen https://eu1.platform.bird.com auf. Die SDKs lesen die Region aus Ihrem Schlüssel und legen daher keinen Host fest.
const msg = await bird.whatsapp.send({
to: "+15551234567",
template: {
slug: "bird_otp",
parameters: { code: "123456" },
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+15551234567",
template="bird_otp",
language="en",
parameters={"code": "123456"},
)
print(msg.id, msg.status)msg, err := client.Whatsapp.Send(context.Background(), bird.WhatsappSendParams{
To: "+15551234567",
Template: "bird_otp",
Language: "en",
Parameters: map[string]any{"code": "123456"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)$message = $bird->whatsapp->send(
to: '+15551234567',
template: 'bird_otp',
language: 'en',
parameters: ['code' => '123456'],
);
echo $message->getId(), ' ', $message->getStatus();bird whatsapp send \
--language en \
--parameters '{"code":"123456"}' \
--template bird_otp \
--to +15551234567curl -X POST "https://{region}.platform.bird.com/v1/whatsapp/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "+15551234567",
"template": {
"slug": "bird_otp",
"language": "en",
"parameters": {
"code": "123456"
}
}
}'Das Kundenservice-Fenster
Welche der beiden Arten Sie senden können, hängt von einem einzigen Zustand ab: ob das Kundenservice-Fenster geöffnet ist.
Der Kontakt öffnet das Fenster, indem er Ihrer Geschäftsnummer schreibt oder sie anruft. Das Fenster bleibt 24 Stunden lang geöffnet und beginnt jedes Mal neu, wenn der Kontakt Ihnen erneut schreibt. Solange es geöffnet ist, können Sie eine Servicenachricht senden, also beliebige freie Inhalte: Text, Bild, Video, Audio, Sticker, Dokument, Standort, Kontaktkarten oder interaktive Inhalte. Nach Ablauf erreicht den Kontakt nur noch eine vorab genehmigte Vorlage, und seine Antwort darauf öffnet das Fenster erneut.
Bird verfolgt das Fenster für Sie. Eine Servicenachricht an ein geschlossenes Fenster wird daher abgelehnt, bevor etwas erstellt oder berechnet wird: Die Anfrage gibt 422 E15044 WhatsAppServiceWindowClosed zurück. Die Prüfung erfolgt nach bestem Bemühen und lässt im Zweifel durch. Ein 202 beweist also nicht, dass das Fenster beim Versand tatsächlich geöffnet war. Läuft das Fenster zwischen Annahme und Versand ab, schlägt die Nachricht asynchron fehl, mit service_window_expired im last_error der Nachricht.
Den vollständigen Ablauf beschreibt das Kundenservice-Fenster: was es öffnet, was es neu startet und wie es mit der Preisgestaltung zusammenhängt.
Payload aufbauen
Empfänger
to nennt ein einziges Ziel, angegeben als Telefonnummer, unternehmensbezogene Benutzer-ID oder Gruppen-ID. Eine Telefonnummer hat das E.164-Format: ein führendes +, die Landesvorwahl und die Teilnehmernummer, zum Beispiel +14155550100. Wir validieren die Nummer. Ein Wert, der keine echte, wählbare Nummer sein kann (falsche Länge, nicht vergebenes Präfix), wird deshalb mit 422 WhatsAppInvalidRecipient abgelehnt, bevor etwas berechnet wird. Es gibt kein Empfänger-Array und keinen Massenversand. Um viele Personen zu erreichen, die nicht in einer Gruppe sind, senden Sie daher einen Aufruf pro Empfänger.
Eine unternehmensbezogene Benutzer-ID wie US.13491208655302741918 adressiert einen Kontakt, dessen Telefonnummer Sie nicht haben. So antworten Sie einem Kontakt, der Sie ohne Telefonnummer erreicht hat. Dabei ändern sich zwei Dinge: Die sendende Nummer muss zum selben Business-Portfolio gehören, auf das die ID bezogen ist, und eine Vorlage für Einmal-Bestätigungscodes benötigt eine Telefonnummer. Eine von Bird verwaltete Vorlage wird bereits bei der Annahme mit 422 WhatsAppRecipientNotSupportedForTemplate abgelehnt. Eine Authentifizierungsvorlage, die Ihr Workspace erstellt hat, wird angenommen und schlägt dann fehl, da Meta dafür eine Telefonnummer verlangt.
to akzeptiert noch eine weitere Form: eine WhatsApp-Gruppen-ID wie wag_01krdgeqcxet5s7t44vh8rt9mg, die an alle Teilnehmer dieses Gruppenchats sendet. Ein Gruppenversand lässt from weg und meldet die Zustellung für die gesamte Gruppe statt für einen einzelnen Empfänger. Deshalb behandelt An eine WhatsApp-Gruppe senden dieses Thema auf einer eigenen Seite.
Vorlage
template nennt die vorab genehmigte Vorlage, die gesendet wird:
slug(erforderlich): der Slug der Vorlage, zum Beispielbird_order_confirmation. Er muss einer Vorlage in Ihrem Katalog entsprechen (Kleinbuchstaben, Ziffern und Unterstriche).language: das Sprach-Tag der Vorlage, zum Beispielenoderpt-BR. Lassen Sie es weg, um die Standardsprache der Vorlage zu senden. Wenn Sie eine Sprache angeben, die die Vorlage nicht hat, erhalten Sie422mit einer Liste der vorhandenen Sprachen. Die angenommene Nachricht gibt die aufgelöste Sprache zurück.parameters: die Werte für die Variablen der Vorlage, als ein Objekt mit Namen als Schlüsseln (siehe Komponenten und Parameter). Lassen Sie es bei einer Vorlage ohne Variablen weg.components: dieselben Werte in der Komponentenform von Meta, anstelle vonparameters. Einige Vorlagen akzeptieren nur diese Form.
Ihre Vorlagen, ihre Sprachen und eine gerenderte Vorschau jeder Vorlage finden Sie auf der Seite Templates.
Komponenten und Parameter
Templates enthalten Variablen, entweder benannt ({{ref}}, {{amount}}) oder nummeriert ({{1}}, {{2}}). Sie füllen sie über parameters als ein einziges Objekt. Das variables der Template-Version listet die Schlüssel auf, die es akzeptiert, und kennzeichnet die optionalen. Jeder Schlüssel ist einer der folgenden:
- der Name einer benannten Variable, etwa
order_id - die Nummer einer nummerierten Variable, etwa
1 header_url,header_filenameoderheader_locationfür einen Medien- oder Standort-Header sowieheader_url_1,header_url_2usw. für den Header einer Karussellkartebutton_urlfür das nummerierte Suffix eines URL-Buttons sowiebutton_url_1,button_url_2usw. für den Button einer Karussellkarte. Ein benanntes Suffix verwendet seinen eigenen Namen.codefür den Code eines Authentifizierungs-Templates und für den Wert eines Code-kopieren-Buttons- eine Eingabe, die die Parameterbindungen der Sprache auslesen
Jeder Wert ist ein String, eine Zahl oder ein Boolean. header_location erwartet ein Objekt mit latitude und longitude. Wenn Sie einen Medien-Header weglassen, wird das genehmigte Beispiel des Templates gesendet. Ein aus Meta importiertes Template hat kein Beispiel und benötigt daher den Schlüssel des Medien-Headers. Schlüssel, die die Sprache nicht verwendet, werden ignoriert.
{
"to": "+15551234567",
"from": "+13124495648",
"template": {
"slug": "order_update",
"language": "en",
"parameters": { "order_id": "A-4192", "first_name": "Ava" }
}
}Übergeben Sie das Objekt im CLI mit --parameters:
bird whatsapp send --to +15551234567 --from +13124495648 \
--template order_update --language en \
--parameters '{"order_id":"A-4192","first_name":"Ava"}'Ein Authentifizierungs-Template, dessen Text {{1}} is your verification code lautet und dessen Button den Code kopiert, erhält den Code einmal als code. Bird setzt ihn sowohl in den Text als auch in den Button ein:
{
"parameters": { "code": "481920" }
}Eine Sprache, deren Bindungen Kontaktdaten auslesen, etwa bird.contact.first_name, lässt sich nicht als einzelne Nachricht senden und gibt E15091 zurück. Senden Sie sie stattdessen in einem Broadcast, in dem der Kontakt jedes Empfängers die Werte liefert. Ein Broadcast überspringt Empfänger, deren Kontaktdaten einen Pflichtwert leer lassen. Senden Sie entweder parameters oder components, nicht beides. Einige Templates akzeptieren nur parameters: Templates, deren Sprache ihre Werte mit Parameterbindungen berechnet, und Templates mit benannten Variablen in einer Karussellkarte oder einer Button-URL.
Manche Templates akzeptieren nur components, weil ein einzelner Schlüssel ihre Platzhalter nicht unterscheiden kann. Das ist der Fall, wenn ein Template {{1}} in mehr als einem Block nummeriert, etwa im Header und im Body. Es tritt auch auf, wenn ein Block zwei URL-Buttons mit nummerierten Suffixen enthält oder eine {{button_url}}-Variable neben einem nummerierten URL-Button steht. Wenn Sie ein solches Template mit parameters senden, erhalten Sie 422.
Ein Template nach Komponenten befüllen. components ist die Alternative zu parameters und die einzige Form für ein Template, das sich nicht über einen einzelnen Schlüssel ansprechen lässt. Jede Komponente nennt einen type (header, body, button oder carousel) und ein parameters-Array. Ein carousel erwartet stattdessen ein cards-Array mit einem Eintrag pro genehmigter Karte, in der Reihenfolge der Genehmigung. Jede Karte enthält ihr eigenes components-Array mit Einträgen vom Typ header, body und button. Jeder Parameter nennt seinen eigenen type (text, image, video, gif, document oder location) und enthält das passende Feld: text einen einfachen String, image/video/gif/document eine öffentliche https url und location einen Punkt auf der Karte. Ein Template mit benannten Parametern verlangt bei jedem Parameter ein name, das genau den im Template deklarierten Namen entspricht (siehe Feldreferenz). Ein positionelles Template lässt name weg und übernimmt seine Werte stattdessen in der Reihenfolge von {{n}}, sodass der erste Parameter {{1}} befüllt. In beiden Fällen führen Parameter, die nicht zur Deklaration des Templates passen, zu einem 422 WhatsAppTemplateParameterMismatch. Eine header-Komponente wird bei einem von Bird verwalteten Template verworfen, da kein von Bird verwaltetes Template eine Header-Variable deklariert. Bei einem Template, das Ihr Workspace erstellt hat, wird sie weitergeleitet. So erhält ein Utility- oder Marketing-Template mit Medien-Header sein Bild.
Dasselbe Bestätigungscode-Template übernimmt den Code positionell sowohl als Body-Parameter als auch als Button-Parameter (ohne name):
{
"components": [
{ "type": "body", "parameters": [{ "type": "text", "text": "481920" }] },
{ "type": "button", "parameters": [{ "type": "text", "text": "481920" }] }
]
}Kategorie und Absender
Die Kategorie eines Templates (authentication, utility oder marketing) bestimmt, wie WhatsApp die Nachricht behandelt und, zusammen mit dem Zielland, was sie kostet.
Wem der Absender gehört, entscheidet darüber, ob Sie ihn angeben:
- Ein von Bird verwaltetes Template (sein Slug beginnt mit
bird_) wird von der Nummer gesendet, die Bird für diese Kategorie vorhält. Lassen Siefromdaher weg. Wenn Sie es setzen, erhalten Sie einen422WhatsAppSenderNotAllowed. - Alles andere gibt seinen eigenen Absender in
froman: Service-Nachrichten jedes Typs und jedes Template, das Ihr Workspace erstellt hat. Die Nummer muss Ihrem Workspace gehören. Fehlt sie, erhalten Sie einen422WhatsAppSenderRequired. Eine Nummer, von der der Workspace nicht senden kann, führt zu einem422WhatsAppSenderNotFound. Ein selbst erstelltes Template muss außerdem im selben WhatsApp Business Account liegen wie die Nummer, sonst gibt der Sendeaufruf einen422WhatsAppSenderWABAMismatchzurück.
Einrichtung von Telefonnummern beschreibt beide Nummerntypen und wie Sie eine eigene Nummer verbinden.
Service-Nachrichten
Statt template enthält die Anfrage genau eines der Felder text, image, video, audio, sticker, document, location, contact_cards oder interactive. Alle neun sind Service-Nachrichten und benötigen daher ein offenes Kundenservice-Fenster. Jede von ihnen verlangt außerdem from, eine Nummer, die Ihrem Workspace gehört. Die verwalteten Nummern von Bird können sie nicht übertragen.
text:{ "body": "..." }, bis zu 4.096 Zeichen. Fügen Sie"preview_url": truehinzu, um eine Linkvorschau für die erste URL inbodyanzuzeigen.image,video,audio,sticker,document: Jeder Typ nimmt eine öffentlichehttps-URL entgegen, die WhatsApp beim Senden abruft (url). Eine signierte URL muss daher länger gültig bleiben als der Sendevorgang. Einehttp-URL wird sofort abgelehnt. WhatsApp ruft die Datei selbst ab. Eine URL, die es nicht erreicht, eine URL mit einem nicht unterstützten Typ oder eine Datei über der Größengrenze ihres Typs wird daher angenommen und schlägt danach fehl, mitmedia_rejectedimlast_errorder Nachricht und dem eigenen Grund von WhatsApp indescription.image,videounddocumentakzeptieren zusätzlich ein optionalescaption;documentakzeptiert zusätzlich ein optionalesfilename;audioakzeptiert ein optionales Flagvoice, um die Datei als Sprachnachricht darzustellen.location:{ "latitude": ..., "longitude": ... }(beide erforderlich, in Dezimalgrad) sowie optionalnameundaddress.contact_cards: ein Array mit bis zu fünf Kontakten, die in einer Nachricht geteilt werden. Dasnamejeder Karte benötigtformatted_nameund mindestens einen weiteren Teil (first_name,last_name,middle_name,prefixodersuffix);phone_numbers,emails,urlsundaddressesnehmen jeweils bis zu zehn Einträge auf, undorgundbirthday(alsYYYY-MM-DD) sind optional. Enthält eine Karte einephone_numberim E.164-Format, erhält sie eine Schaltfläche, die einen Chat mit dieser Nummer öffnet.interactive: Fließtext plus ein antippbares Element in einem von sechs Typen: Antwortschaltflächen, ein Listenmenü, eine Link-Schaltfläche, ein Medienkarussell oder eine einzelne Schaltfläche, die den Empfänger nach seinem Standort oder seiner Telefonnummer fragt. Interaktive Nachrichten beschreibt das Format jedes Typs, die Antworten, die ein Tippen auslöst, und die Grenzwerte.
{
"to": "+16505551234",
"from": "+13124495648",
"text": { "body": "Your order shipped: https://example.com/track/A1B2C3", "preview_url": true }
}Eine Anfrage ohne Inhalt oder mit mehr als einem Inhaltstyp wird mit einem 422 abgelehnt.
Eine Nachricht zitieren
Setzen Sie in_reply_to_message_id auf eine WhatsApp-Nachrichten-ID, um Ihre Nachricht als Antwort darauf zu senden, so wie das Tippen auf „Antworten“ in der WhatsApp-App eine Nachricht zitiert. Der Empfänger sieht Ihre Nachricht mit der zitierten Nachricht darüber, und das Feld wird bei jedem Lesen der Nachricht zurückgegeben.
Das funktioniert auch umgekehrt: Eine eingehende Nachricht, die WhatsApp als Antwort kennzeichnet, enthält im selben Feld die ID der zitierten Nachricht. So erkennen Sie, auf welche Ihrer Nachrichten eine Antwort sich bezieht. Eine eingehende Nachricht, die WhatsApp nicht kennzeichnet, enthält keine ID, und auch die Auflösung kann fehlschlagen. Für eine zuverlässige Zuordnung verwenden Sie explizite interaktive Antwortkennungen zusammen mit dem Konversations- oder Aufgabenstatus, den Ihre Anwendung speichert. Ausgehende metadata bleiben am ausgehenden Datensatz und werden nicht automatisch in die Antwort übernommen.
Das Zitat wird aufgelöst, bevor der Sendevorgang angenommen wird. Ein Zitat, das sich nicht darstellen lässt, lässt daher die Anfrage selbst fehlschlagen, und es wird nichts erstellt oder berechnet. Eine ID, die keine Nachricht in diesem Workspace bezeichnet, oder eine Nachricht, die älter als die 15 Tage ist, in denen sie zitierbar bleibt, gibt einen 404 E15071 WhatsAppReferencedMessageNotFound zurück. Eine ID, die eine Nachricht bezeichnet, die WhatsApp nie erreicht hat, oder eine Nachricht aus einer anderen Konversation als der durch to und from dieses Sendevorgangs bestimmten, gibt einen 422 E15072 WhatsAppMessageNotQuotable zurück. Kann Bird den Speicher, der diese Frage beantwortet, nicht erreichen, gibt der Sendevorgang einen 503 E15073 WhatsAppMessageLookupUnavailable zurück; in diesem Fall lohnt es sich, es erneut zu versuchen. Zitieren funktioniert bei Vorlagen und bei frei formulierten Nachrichten gleichermaßen.
{
"to": "+16505551234",
"from": "+13124495648",
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"text": { "body": "Yes, that slot is still free." }
}Tags und Metadaten
Mit drei optionalen Feldern hängen Sie eigenen Kontext an eine Nachricht an. Alle drei werden beim Lesen über API zurückgegeben und sind in jedem Webhook-Ereignis zur Nachricht enthalten:
tags: bis zu 20 strukturierte{ "name": ..., "value": ... }-Labels für Dimensionen mit wenigen Ausprägungen, nach denen Sie filtern und auswerten (eine Kampagne, eine Testvariante). Namen und Werte bestehen aus ASCII-Buchstaben, Ziffern, Unterstrich und Bindestrich. Namen sind auf 32 Zeichen begrenzt und innerhalb eines Sendevorgangs eindeutig, Werte auf 64 Zeichen. Filtern Sie die Nachrichtenliste nach Tag (?tag=campaignoder?tag=campaign:launch-week); die Seite Metrics schlüsselt die Zustellung nach Tag auf.metadata: ein beliebiges JSON-Objekt mit bis zu 2 KB in serialisierter Form, für Kontext pro Sendung, den Sie nicht als Filterdimension benötigen (eine interne Bestell-ID, eine Sitzungsreferenz).reference: eine Zeichenkette mit 1 bis 255 Zeichen, über die Sie die Nachricht wiederfinden möchten, etwa eine Bestell- oder Ticketnummer.?reference=in der Nachrichtenliste findet sie nur bei exakter Übereinstimmung unter Beachtung der Groß- und Kleinschreibung, und mehrere Nachrichten können denselben Wert haben. Setzen Sie das Feld nur, wenn Sie danach suchen müssen, und legen Sie alle anderen Daten inmetadataab.
{
"tags": [{ "name": "campaign", "value": "order-confirmations" }],
"metadata": { "order_id": "ord_8271" },
"reference": "ord_8271"
}Feldreferenz
| Feld | Typ | Erforderlich | Grenzen / Hinweise |
|---|---|---|---|
to | string | ja | Ein Empfänger pro Nachricht: eine E.164-Telefonnummer, eine unternehmensbezogene Nutzer-ID, die von keiner Vorlage für Einmal-Bestätigungscodes akzeptiert wird, oder eine WhatsApp-Gruppen-ID (wag_…), die an alle Teilnehmer dieser Gruppe sendet |
from | string (E.164) | nein** | Bei einer Bird-verwalteten Vorlage weglassen, da sie ihren Absender selbst wählt, ebenso bei einem Gruppenversand, der die eigene Nummer der Gruppe verwendet; erforderlich für eine Servicenachricht und für eine von Ihrem Workspace erstellte Vorlage, und es muss eine Nummer sein, die Ihrem Workspace gehört |
template.slug | string | nein** | Ein Vorlagen-Slug, den Ihr Workspace senden kann; Bird-verwaltete Slugs beginnen mit bird_ |
template.language | string | nein* | Sprach-Tag der Vorlage (en, pt-BR); weglassen, um die Standardsprache der Vorlage zu senden |
template.parameters | object | nein | Füllt die Variablen der Vorlage nach Namen, etwa ref oder code; höchstens 16 KB, und bird ist reserviert |
template.components | array | nein | Die Alternative zu parameters, ein Eintrag pro Komponente: type ist header, body, button oder carousel, und ein carousel erwartet cards statt parameters |
template.components[].parameters[].name | String | nein† | Der Platzhalter, den dieser Wert füllt, etwa ref; bei einer Vorlage mit benannten Parametern erforderlich und muss den deklarierten Namen der Vorlage entsprechen, bei einer positionellen Vorlage weglassen |
text | object | nein** | {body, preview_url?} Service-Nachricht als reiner Text (bis zu 4.096 Zeichen); siehe Reiner Text |
image, video, audio, sticker, document | object | nein** | Service-Nachricht mit Medien, mit url (und optional caption oder filename, sofern unterstützt); siehe Service-Nachrichten |
location | object | nein** | {latitude, longitude, name?, address?}-Standortmarkierung; siehe Standorte |
contact_cards | array | nein** | Bis zu 5 strukturierte vCard-Kontaktobjekte; siehe Kontaktkarten |
interactive | object | nein** | Nachrichtentext plus eine Art antippbarer Inhalte; eine Servicenachricht, daher ist ein offenes Servicefenster nötig. Siehe Interaktive Nachrichten |
in_reply_to_message_id | string | nein | Eine WhatsApp-Nachrichten-ID aus diesem Workspace, die in Ihrer gesendeten Nachricht zitiert wird; wird beim Lesen zurückgegeben. Siehe Eine Nachricht zitieren |
tags | Array | nein | Bis zu 20 {name, value}-Labels; Name ≤ 32 Zeichen, Wert ≤ 64, Namen eindeutig |
reference | String | nein | 1–255 Zeichen; exakte Übereinstimmung für ?reference= in der Nachrichtenliste |
metadata | Objekt | nein | Beliebiges JSON, serialisiert bis zu 2 KB |
* language ist optional; ohne Angabe wird die Standardsprache der Vorlage gesendet.
† name ist bei einer Vorlage mit benannten Parametern für jeden Parameter erforderlich. Bei einer positionellen Vorlage lassen Sie es weg. Siehe Komponenten und Parameter.
** Senden Sie genau eines von template oder einem Inhaltsfeld für Servicenachrichten (text, image, video, audio, sticker, document, location, contact_cards, interactive); siehe Servicenachrichten.
Das asynchrone Modell: was 202 bedeutet
Ein erfolgreicher Versand gibt 202 Accepted mit einer Nachrichten-ID und status: accepted zurück. 202 wird erst zurückgegeben, wenn der Versand dauerhaft angenommen ist; eine angenommene Nachricht wird nie stillschweigend verworfen. Harte Fehler, die Sie beheben können, schlagen sofort mit 422 fehl: ein ungültiger Empfänger, ein unbekannter Template-Slug oder eine unbekannte Sprache, nicht passende Parameter oder eine Servicenachricht in ein geschlossenes Kundenservice-Fenster (WhatsAppServiceWindowClosed). Ein ungedecktes Wallet gehört nicht dazu: Der Versand wird angenommen, und die Nachricht endet mit rejected und insufficient_balance, sobald Bird versucht, sie abzurechnen. Die eigentliche Zustellung erfolgt asynchron: Die Nachricht wechselt zu sent, wenn wir sie an WhatsApp übergeben, und dann in einen Endstatus (delivered oder failed), wenn die Empfangsbestätigung eintrifft. Das melden Events, Webhooks und die Lese-Endpunkte. Eine Lesebestätigung erscheint nicht als Status, sondern separat als Zeitstempel read_at und als Event whatsapp.read.
Ein Hinweis zum Datenschutz: Bei Templates der Kategorie authentication gibt API die eingesetzten Werte nie zurück. Das Echo von 202 und jeder spätere Lesezugriff enthalten für diese Nachrichten ein leeres Array components, sodass ein Bestätigungscode nie wieder auftaucht.
Sicher erneut versuchen
Senden Sie den Header Idempotency-Key mit einem eindeutigen Wert pro logischem Versand, dann sind erneute Versuche sicher. Wenn Ihre erste Anfrage erfolgreich war, Sie die Antwort aber nie erhalten haben (Timeout, abgebrochene Verbindung), liefert eine Wiederholung mit demselben Schlüssel das ursprüngliche Ergebnis zurück. Es wird also keine doppelte Nachricht gesendet und abgerechnet. Die wiederholte Antwort enthält einen Header Idempotency-Replay. Schlüsselformat und Aufbewahrungsdauer beschreibt Idempotenz.
Die Antwort empfangen
Eingehende Nachrichten landen auf derselben Ressource wie ausgehende, und jede von ihnen setzt das Service-Fenster zurück. WhatsApp-Nachrichten empfangen beschreibt, wie Sie sie über API lesen, die von einem Kontakt gesendeten Medien abrufen und den Webhook whatsapp.received nutzen.
Kosten und Abrechnung
WhatsApp wird pro Nachricht abgerechnet, abhängig von der Kategorie des Templates und dem Land des Empfängers; siehe WhatsApp-Preise. Eine Nachricht wird in zwei Schritten zu zwei verschiedenen Zeitpunkten abgerechnet, und das Objekt cost der Nachricht meldet beide:
| Feld | Bedeutung | Zeitpunkt |
|---|---|---|
transaction_amount | Gebühr von Bird für die Abwicklung des Versands | Wenn Bird den angenommenen Versand verarbeitet, vor der Zustellung |
passthrough_amount | Metas Anteil am Nachrichtenpreis, den Bird weiterberechnet | Wenn eine zutreffende delivered- oder read-Bestätigung eingeht |
amount | Die Summe der bisher bepreisten Komponenten | Wächst mit jeder hinzukommenden Komponente |
currency_code | Die Währung der Wallet Ihrer Organisation, gilt für beide Komponenten | Mit der ersten Komponente |
Beide Beträge sind Dezimalzeichenfolgen ohne Steuern.
Hinweis: Für eine Servicenachricht fällt bis zum 30. September 2026 kein Meta-Anteil an, ebenso wenig für eine Utility-Vorlage, die innerhalb eines offenen Kundenservice-Fensters zugestellt wird. Ab dem 1. Oktober 2026 berechnet Meta beides, außer innerhalb eines 72-stündigen kostenlosen Einstiegsfensters und mit 1.000 kostenlosen Servicenachrichten pro geschäftlicher Telefonnummer und Monat: Preisänderungen im Oktober 2026.
Die beiden Komponenten werden auf Grundlage unterschiedlicher Angaben berechnet. Die Gebühr von Bird richtet sich nach der Kategorie der gesendeten Vorlage und dem Land des Empfängers. Das Land ergibt sich aus der Ländervorwahl der Telefonnummer oder, bei einem Versand an eine unternehmensbezogene Benutzer-ID, aus dem zweibuchstabigen Präfix dieser ID. Der Meta-Anteil richtet sich nach der Kategorie, die Meta selbst in der maßgeblichen Empfangsbestätigung meldet, und diese kann von der Kategorie der Vorlage abweichen: Meta kann authentication-international melden, wenn die eigenen Regeln zu Zielland, Unternehmensstandort und Berechtigung greifen. Siehe WhatsApp-Tarife für authentication-international.
Was cost enthält, hängt davon ab, wie weit die Nachricht schon gelangt ist:
- Bei der
202istcostnull. Es wurde noch nichts berechnet. - Nach der Verarbeitung ist
transaction_amountgesetzt, undamounthat denselben Wert.passthrough_amountbleibt null. - Nach einer maßgeblichen
delivered- oderread-Empfangsbestätigung füllt eine erfolgreich erfasste Meta-Gebührpassthrough_amount, undamountspiegelt die erfassten Komponenten wider.
Eine Komponente mit dem Wert null bedeutet, dass in dieser Projektion kein Betrag erfasst ist. Sie beweist nicht, dass die Nachricht kostenlos war. Eine Komponente, die ausdrücklich mit null berechnet wurde, enthält "0.00000".
Die beiden Gebühren schlagen auch unterschiedlich fehl. Die Gebühr von Bird schlägt geschlossen fehl: Kann sie nach dem 202 nicht abgebucht werden, weil das Guthaben den Versand nicht deckt oder für die Route kein Preis konfiguriert ist, endet die Nachricht mit rejected und dem Fehlercode insufficient_balance oder price_not_found, und es wird nichts berechnet. Eine Nachricht mit rejected hat WhatsApp nie erreicht, und das unterscheidet sie von failed. Der Meta-Anteil schlägt offen fehl: Reicht das Guthaben nicht oder fehlt der Tarif beim Eingang der Empfangsbestätigung, wird die Gebühr übersprungen, ohne den beobachteten Nachrichtenstatus rückgängig zu machen. Die zweite Gebühr hält Ihre Zustellung nie auf.
Eine Nachricht, für die Bird eine Gebühr berechnet hat, behält diese ausgehende Gebühr, auch wenn die Zustellung später fehlschlägt. Die Meta-Gebühr wird aus einem maßgeblichen delivered- oder read-Callback verarbeitet, wenn Meta reguläre Preise mit einer auflösbaren Kategorie und einem auflösbaren Ziel meldet. Beide Callback-Wege verwenden dieselbe Gebührenidentität und stützen sich auf die Deduplizierung des Abrechnungsdienstes. Gleichen Sie wiederholt eingehende Empfangsbestätigungen mit den Abrechnungsdatensätzen ab, statt die Nachrichtenprojektion als dauerhaften Abbuchungsbeleg zu behandeln. Service- oder Gratis-Einstiegspreise können die Meta-Komponente auf null setzen. Eine nicht aufgelöste Komponente belegt nicht, dass die Nachricht kostenlos war.
Verwenden Sie für den finanziellen Abgleich das Abrechnungsjournal. Die cost-Felder einer Nachricht sind Projektionen der Gebühren und können verzögert oder unvollständig sein. Unter WhatsApp-Metriken finden Sie den Unterschied zwischen Nachrichtenbeobachtungen und Abrechnungsdatensätzen.
WhatsApp-Events enthalten keine Kosten. Um eine der beiden Komponenten abzurufen, lesen Sie die Nachricht mit GET /v1/whatsapp/messages/{id} erneut aus.
Nächste Schritte
- Service-Nachrichten: Text, Medien und interaktive Inhalte innerhalb des Kundenservice-Fensters senden
- Templates: ein Template auswählen und seine Variablen befüllen
- WhatsApp-Nachrichten empfangen: Antworten lesen und eingehende Medien abrufen
- Webhooks für den Nachrichtenstatus: Updates zu Zustellung und Fehlschlägen empfangen
- Idempotenz: Anfragen mit dem Header
Idempotency-Keysicher erneut versuchen
Verwandte Ressourcen
Weiter mit der Dokumentation, Anleitungen und Beispielen zu diesem Thema.