Zdarzenia WhatsApp
Bird rejestruje zdarzenia dla przychodzących i wychodzących wiadomości WhatsApp. Oś czasu wiadomości wychodzącej pokazuje, co się stało po tym, jak wysyłka zwróciła 202: akceptacja, przekazanie do WhatsApp, dostarczenie, odczytanie lub niepowodzenie. Oś czasu wiadomości przychodzącej rejestruje, kiedy Bird odebrał wiadomość.
Koperta zdarzenia
Zdarzenia dostarczenia, wiadomości przychodzących i reakcji WhatsApp używają standardowej koperty webhooka: type, timestamp oraz obiekt data specyficzny dla danego typu.
Przykład kodu
{
"data": {
"direction": "outbound",
"from": { "phone_number": "+13124495569" },
"metadata": { "session_id": "sess_4821" },
"tags": [{ "name": "flow", "value": "login-otp" }],
"to": { "phone_number": "+14155550100" },
"whatsapp_id": "wam_01ky7qbvswf3fvyaw3az90391c",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
},
"timestamp": "2026-07-23T14:51:39.913Z",
"type": "whatsapp.delivered"
}Każdy publiczny ładunek webhooka WhatsApp dla wiadomości zawiera whatsapp_id, workspace_id, direction, from, to, tags i metadata. Wyjątkiem jest whatsapp.reacted, ponieważ reakcja to adnotacja do wiadomości, a nie osobna wiadomość; sekcja Reakcje poniżej opisuje jej kształt. Adres może zawierać numer E.164 w phone_number, identyfikator użytkownika Meta o zasięgu biznesowym w bsuid lub oba. Wiadomość odebrana od użytkownika WhatsApp zawiera też profil, który publikuje, w username i display_name. tags i metadata mają wartość null, gdy wysyłka ich nie zawierała. Wiadomość wysłana jako odpowiedź zawiera też in_reply_to_message_id w każdym zdarzeniu wychodzącym na osi czasu, od whatsapp.accepted przez whatsapp.read, whatsapp.failed lub whatsapp.rejected, wskazując wiadomość, na którą odpowiada.
API zdarzeń zwraca lżejsze rekordy osi czasu z id, type i znacznikiem czasu occurred_at. Identyfikator wiadomości jest już w adresie URL żądania.
Zdarzenia cyklu życia
Zdarzenia pojawiają się w kolejności chronologicznej. Wiadomość wychodząca może zakończyć się na whatsapp.failed lub whatsapp.rejected, a jej zdarzenie whatsapp.read pojawia się tylko wtedy, gdy odbiorca otworzy wiadomość. Oś czasu wiadomości przychodzącej zaczyna się od whatsapp.received i może zarejestrować whatsapp.read po tym, jak Twój obszar roboczy oznaczy wiadomość jako przeczytaną.
| Zdarzenie | Znaczenie |
|---|---|
| whatsapp.accepted | Bird zaakceptował żądanie wysyłki. To jest to, co zgłosił 202. |
| whatsapp.sent | Bird przekazał wiadomość do sieci WhatsApp. |
| whatsapp.delivered | WhatsApp potwierdził dostarczenie na urządzenie odbiorcy. |
| whatsapp.read | Odbiorca otworzył wiadomość. |
| whatsapp.failed | Wiadomość nie została dostarczona. error.code podaje przyczynę. |
| whatsapp.rejected | Bird odrzucił wiadomość przed wysłaniem. Nie została naliczona opłata. |
| whatsapp.received | Bird odebrał wiadomość przychodzącą od kontaktu. |
Odpowiednie callbacki delivered lub read mogą uruchomić naliczenie opłaty Meta. Payloady zdarzeń WhatsApp nie zawierają kosztu. Odczytaj wiadomość za pomocą GET /v1/whatsapp/messages/{message_id}, żeby sprawdzić, ile kosztowała. Zobacz Koszty i rozliczenia.
Oznaczenie wiadomości przychodzącej jako przeczytanej zapisuje whatsapp.read na jej osi czasu, ale nie emituje webhooka potwierdzenia odczytu. Wiadomość przychodząca zachowuje status received i zapisuje read_at po tym, jak WhatsApp zaakceptuje potwierdzenie.
whatsapp.read nie zmienia status wiadomości. Dostarczona wiadomość pozostaje w stanie delivered; wiadomość dodatkowo rejestruje odczyt w read_at.
whatsapp.delivered może zostać całkowicie pominięte. Gdy odbiorca ma już otwarty czat na swoim urządzeniu, Meta zgłasza odczyt bez wcześniejszego zgłoszenia dostarczenia, więc oś czasu wygląda tak: whatsapp.accepted → whatsapp.sent → whatsapp.read bez whatsapp.delivered pomiędzy. Traktuj read jako dowód dostarczenia: konsument, który czeka na delivered przed uznaniem wiadomości za dostarczoną, zawiesi się dokładnie na tych odbiorcach, którzy zobaczyli ją najszybciej, a konsument obliczający wskaźnik dostarczenia wyłącznie z delivered zaniży go. status wiadomości pozostaje w stanie sent w tym przypadku, ponieważ tylko potwierdzenie dostarczenia go zmienia.
Callback samego odczytu wciąż może wywołać naliczenie odpowiedniej opłaty Meta. Bird używa jednej tożsamości opłaty na ścieżkach dostarczenia i odczytu; brak zdarzenia dostarczenia nie oznacza darmowego komponentu Meta. Zobacz Koszty i rozliczenia.
Lista typów zdarzeń jest otwarta: nowe typy mogą być dodawane z czasem, więc traktuj nierozpoznaną wartość jako przyszłe zdarzenie, a nie błąd.
Zdarzenia niepowodzenia
whatsapp.failed i whatsapp.rejected są terminalne. Odrzucenie (rejection) oznacza, że Bird zatrzymał wiadomość przed wysłaniem jej do WhatsApp, więc nie została naliczona opłata. Przyczynami mogą być zablokowany lub wypisany odbiorca, niewystarczające saldo portfela lub miejsce docelowe bez skonfigurowanej ceny. Niepowodzenie (failure) oznacza, że wiadomość nie została dostarczona, a error.code wskazuje, kto o tym zadecydował. Większość kodów zawiera werdykt WhatsApp, zmapowany z kodu, który zgłosił. Wyjątkiem jest internal_error: rejestruje brakujące użyteczne poświadczenie nadawcy lub wyczerpane ponowienia przetwarzania. Niepewna próba transportu nie dowodzi, że Meta nigdy nie otrzymała żądania. meta_error_code zawiera kod WhatsApp, gdy jest dostępny, a niepowodzenie internal_error z założenia go nie ma.
Oba zdarzenia zawierają obiekt error ze stabilnym Bird code, czytelnym dla człowieka description, opcjonalnym meta_error_code oraz occurred_at. Obiekt pojawia się w rekordach API i payloadach webhooków tylko dla tych typów zdarzeń.
Zdarzenia reakcji
Reakcja emoji oznacza istniejącą wiadomość. Nie tworzy wiadomości whatsapp.received. Bird emituje whatsapp.reacted, gdy kontakt dodaje, zmienia lub usuwa reakcję, zgodnie z opisem w Reakcje. Reakcje wysłane przez Twój numer firmowy nie emitują tego webhooka. Zobacz Wysyłanie reakcji, aby dodać, zastąpić lub usunąć swoją reakcję, oraz Odbieranie reakcji, aby zobaczyć przykłady webhooków i REST API. Reakcje kontaktów nie otwierają okna obsługi klienta.
Dziennik reakcji wiadomości, na którą zareagowano, rejestruje zmiany dokonane zarówno przez kontakt, jak i przez Twój numer firmowy: dodania, zastąpienia i usunięcia.
Jeden przypadek nie jest nigdzie rejestrowany. Bird dopasowuje reakcję do wiadomości przez identyfikator dostawcy, który przechowuje przez 15 dni, podczas gdy WhatsApp akceptuje reakcję na wiadomość do 30 dni wstecz, więc reakcja umieszczona na starszej wiadomości nie może zostać dopasowana i nie trafia ani do dziennika, ani do reactions. Wiadomość bez wpisów nie jest zatem dowodem, że nikt na nią nie zareagował.
Odczytuj ten dziennik za pomocą GET /v1/whatsapp/messages/{message_id}/reaction-events, od najnowszych. Wpis zawiera emoji, autora zmiany oraz status o wartości received, sent, failed lub rejected; wpis failed lub rejected zawiera przyczynę w error. Każdy wpis ma identyfikator reakcji (war_…) i znacznik czasu occurred_at. Usunięcie ma emoji: null. Oczekujące zmiany nie mają wpisu, dopóki ich wynik nie jest znany. Reakcja nigdy nie jest płatna, więc żadne niepowodzenie reakcji nie jest rozliczeniowe. Aby zobaczyć, co aktualnie jest przypisane do wiadomości zamiast historii zmian, odczytaj jej reactions za pomocą GET /v1/whatsapp/messages/{message_id}, które redukuje dziennik do jednego wpisu na nadawcę.
Zdarzenia blokowania
Poza cyklem życia poszczególnych wiadomości jedno zdarzenie zgłasza zmianę na liście blokad obszaru roboczego: whatsapp_suppression.created jest emitowane, gdy blokada zostaje otwarta. Ładunek zawiera suppression_id, zablokowany address w formacie E.164, waba, do którego blokada jest ograniczona (null, gdy obejmuje cały obszar roboczy, niezależnie od konta wysyłającego), reason oraz workspace_id, dzięki czemu Twój system może wykrywać nowe blokady bez odpytywania. Tylko otwarcia generują zdarzenie: zakończenie blokady jeszcze tego nie robi, więc ponownie odczytaj listę, zanim uznasz powieloną blokadę za nadal obowiązującą:
Przykład kodu
{
"type": "whatsapp_suppression.created",
"timestamp": "2026-08-25T14:52:03.192524705Z",
"data": {
"suppression_id": "was_01krdgeqcxet5s7t44vh8rt9mg",
"address": "+14155550100",
"waba": null,
"reason": "manual",
"workspace_id": "ws_01ky7m21hjffh9s8kq76gyb1xf"
}
}Rezygnacja zadeklarowana przez samego odbiorcę to preferencja, a nie blokada, i emituje preference.revoked zamiast tego.
Odczytywanie zdarzeń z API
GET /v1/whatsapp/messages/{message_id}/events zwraca oś czasu w kolejności chronologicznej. Lista ograniczona nie jest paginowana. Odczytywanie zdarzeń wymaga klucza API z uprawnieniem whatsapp:read:
const { data } = await bird.whatsapp.listEvents("wa_abc123");
for (const event of data) console.log(event.type, event.occurred_at);events = client.whatsapp.list_events("wa_abc123")
for event in events.data:
print(event.type, event.occurred_at)events, err := client.Whatsapp.ListEvents(context.Background(), "wam_01krdgeqcxet5s7t44vh8rt9mg", bird.WhatsappListEventsParams{})
if err != nil {
log.Fatal(err)
}
for _, e := range events.Data {
fmt.Println(e.Id, e.Type)
}$events = $bird->whatsapp->listEvents('wamid_01krdgeqcxet5s7t44vh8rt9mg');
foreach ($events->getData() ?? [] as $event) {
echo $event->getType(), ' ', $event->getId(), "\n";
}bird whatsapp list-events <message-id>curl https://us1.platform.bird.com/v1/whatsapp/messages/wam_.../events \
-H "Authorization: Bearer $BIRD_API_KEY"Wiadomość, która została zaakceptowana, wysłana, dostarczona i odczytana, zwraca cztery zdarzenia:
Przykład kodu
{
"data": [
{
"id": "ev_01ky7q6a1fejfbvs0myn41hj41",
"occurred_at": "2026-07-23T14:48:34.71Z",
"type": "whatsapp.accepted"
},
{
"id": "ev_01ky7q6a2denvtd6jg1vqwmg13",
"occurred_at": "2026-07-23T14:48:35.671Z",
"type": "whatsapp.sent"
},
{
"id": "ev_01ky7q6a2zff9r2qm74mmg1g6z",
"occurred_at": "2026-07-23T14:48:36.642Z",
"type": "whatsapp.delivered"
},
{
"id": "ev_01ky7q6c21frssf0vj8h50qysw",
"occurred_at": "2026-07-23T14:48:38.65Z",
"type": "whatsapp.read"
}
]
}Przekaż type, aby zwrócić dokładnie jeden publiczny typ zdarzenia, na przykład ?type=whatsapp.failed lub ?type=whatsapp.read. Pomiń go, aby otrzymać pełną oś czasu.
Ta sama oś czasu jest tym, co strona dziennika WhatsApp wyświetla po otwarciu wiadomości.

Webhooki
Subskrybuj whatsapp.accepted, whatsapp.sent, whatsapp.delivered, whatsapp.read, whatsapp.failed, whatsapp.rejected, whatsapp.received i whatsapp.reacted ze strony Webhooks lub z API webhooków. Przewodnik po webhookach opisuje endpointy, sygnatury i ponowienia.
whatsapp.received zawiera treść wiadomości oprócz opisanej wyżej koperty, więc endpoint może obsłużyć wiadomość przychodzącą bez ponownego jej odczytywania. Kliknięcie interaktywnej wiadomości przychodzi jako interactive_reply, a in_reply_to_message_id wskazuje wiadomość, na którą odpowiada:
Przykład kodu
{
"data": {
"direction": "inbound",
"from": {
"display_name": "Alex Rivera",
"phone_number": "+14155550100",
"username": "alexr"
},
"in_reply_to_message_id": "wam_01ky7qbvswf3fvyaw3az90391c",
"interactive_reply": {
"list": {
"description": "Next day to 2 days",
"slug": "priority_express",
"text": "Priority Mail Express"
},
"type": "list"
},
"metadata": null,
"tags": null,
"to": { "phone_number": "+13124495569" },
"whatsapp_id": "wam_01ky8b3xq4gd7pmzn2ka51f7te",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
},
"timestamp": "2026-07-23T14:52:04.118Z",
"type": "whatsapp.received"
}Pozostałe warianty treści mają tę samą strukturę „jedno z tych pól": text, image, video, audio, sticker, document, location, contact_cards oraz unsupported dla rodzaju, którego API nie modeluje. GET /v1/whatsapp/messages/{message_id} dokumentuje każdy z nich.
Reakcje
whatsapp.reacted jest emitowane, gdy użytkownik WhatsApp zareaguje na jedną z Twoich wiadomości. To jedyne zdarzenie WhatsApp, które nie jest częścią osi czasu dostarczenia wiadomości: nie pojawia się w GET /v1/whatsapp/messages/{message_id}/events i nie ma tam możliwości filtrowania po nim.
whatsapp_id wskazuje wiadomość, na którą zareagowano, a nie reakcję, natomiast emoji to zmiana dokonana przez użytkownika. Użytkownik, który zareaguje, zmieni emoji, a potem cofnie reakcję, generuje trzy zdarzenia na tej jednej wiadomości. WhatsApp nie wysyła usunięcia między pierwszymi dwoma, więc zmiana przychodzi jako pojedyncze zdarzenie z nowym emoji.
Przykład kodu
{
"data": {
"emoji": "👍",
"from": { "phone_number": "+14155550100" },
"to": { "phone_number": "+13124495569" },
"whatsapp_id": "wam_01ky8b3xq4gd7pmzn2ka51f7te",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
},
"timestamp": "2026-07-23T14:52:11.000Z",
"type": "whatsapp.reacted"
}WhatsApp raportuje czas reakcji z dokładnością do sekundy, więc dwa z tych trzech zdarzeń mogą mieć ten sam timestamp. Sortowanie po nim nie ustali ich kolejności, podobnie jak kolejność dostarczenia, którą ponowienia czynią zawodną. Reaguj na reakcję, którą niesie każde zdarzenie, jako na opisywaną przez nie zmianę. Nie rekonstruuj sekwencji ze zdarzeń ani nie traktuj ostatniego dostarczonego jako aktualnej reakcji na wiadomość, ponieważ ani znaczniki czasu, ani kolejność dostarczenia tego nie gwarantują. Odczytaj wiadomość, aby sprawdzić aktualne reakcje: GET /v1/whatsapp/messages/{message_id} zwraca jeden wpis na nadawcę w reactions, a dziennik reakcji wiadomości zawiera każdą zmianę.
emoji jest obecne i ma wartość null, gdy użytkownik cofnął swoją reakcję, więc null oznacza samo usunięcie, a nie brakującą wartość. Emoji jest dostarczane dokładnie tak, jak wysłał je WhatsApp, bez normalizacji, więc ❤ i ❤️ docierają do Ciebie jako różne ciągi znaków.
Następne kroki
- Odbieranie reakcji: obsługa webhooków reakcji kontaktów i odczyt aktualnych reakcji
- Wysyłanie reakcji: dodawanie, zastępowanie lub usuwanie własnej reakcji
- Oznacz wiadomość jako przeczytaną: potwierdź wiadomość przychodzącą i pokaż pisanie
- Dziennik WhatsApp: widok pojedynczej wiadomości wyświetlający tę oś czasu
- Wysyłanie wiadomości WhatsApp: tu zaczyna się cykl życia wiadomości
- Przewodnik po webhookach: endpointy, sygnatury, ponowienia i pełny katalog zdarzeń
Powiązane zasoby
Kontynuuj z dokumentacją, przewodnikami i przykładami dotyczącymi tego tematu. Zasoby są w języku angielskim.
Obejrzyj przewodnikConnecting WhatsApp to Bird: from buying a number to a live channelZrozum koncepcjęWhat is the 24-hour customer service window on WhatsApp?Użyj narzędziaWhatsApp message builderPoznaj możliwościWhatsApp
Wypróbuj ćwiczenie i uzyskaj brief wdrożeniowy