Menerima pesan WhatsApp
Pesan masuk tersimpan di resource yang sama dengan pesan keluar, tanpa endpoint inbox terpisah untuk di-poll. Baca pesan melalui daftar pesan di dashboard, atau melalui API dengan GET /v1/whatsapp/messages/{id} setelah memfilter daftar ke pesan masuk.
Setiap pesan masuk memperpanjang jendela layanan pelanggan hingga 24 jam setelah timestamp pesan itu sendiri, yang membuat balasan bebas dari Anda dapat terkirim. Pesan yang tiba di Bird terlambat tetap membawa jendela yang sebenarnya diberikan kontaknya, dan tenggat waktu yang sudah tercatat lebih lama tidak pernah diperpendek.
Isi pesan masuk
Setiap pesan masuk memiliki satu envelope: id, direction: "inbound", kontak di from, nomor Anda di to, status berupa received, dan created_at. Tepat satu field konten menyertainya, menyatakan apa yang dikirim kontak:
Contoh kode
{
"id": "wam_01kya19eknftrs2s6p82asmvnh",
"direction": "inbound",
"from": { "phone_number": "+14155550100" },
"to": { "phone_number": "+13124495569" },
"status": "received",
"text": { "body": "Is my order out for delivery yet?" },
"created_at": "2026-08-25T09:04:11Z"
}from menamai kontak berdasarkan identitas apa pun yang dilaporkan WhatsApp: phone_number E.164, bsuid, atau keduanya, ditambah username dan display_name yang mereka publikasikan. Kontak yang telah menggunakan username WhatsApp dapat menghubungi Anda tanpa nomor telepon sama sekali; lihat business-scoped user ID untuk mengetahui apa yang perlu disimpan dan cara meminta nomor.
Salah satu field konten ini, sebuah arm, membawa apa yang dikirim kontak, dan tepat satu arm yang diisi pada setiap pesan. Masing-masing memiliki halaman tersendiri, dengan bentuk baca, payload whatsapp.received, dan hal yang perlu diperhatikan:
| Field | Isi pesan masuk |
|---|---|
| text | body, pesan yang diketik kontak |
| image | id, url, mime_type, dan caption jika ada |
| video | Field media yang sama, ditambah caption jika ada |
| audio | Field media yang sama, ditambah voice pada voice note; tidak ada caption |
| sticker | Field media yang sama, ditambah animated |
| document | Field media yang sama, ditambah filename dan caption jika ada |
| location | latitude dan longitude, dan terkadang name, address, atau url |
| contact_cards | Satu atau lebih kartu kontak yang dibagikan kontak |
| interactive_reply | slug dan text dari tombol atau baris yang diketuk kontak |
| unsupported | Tipe konten WhatsApp yang tidak dimodelkan API, seperti order |
Dua ketukan tiba pada arm yang mungkin tidak Anda duga. Location request dijawab sebagai location masuk biasa, dan contact info request dijawab sebagai contact_cards, sehingga integrasi yang hanya memantau interactive_reply untuk ketukan akan melewatkan keduanya.
Mengambil media masuk
image, video, audio, sticker, atau document masuk tiba sebagai referensi ke file yang disimpan Bird, bukan sebagai file itu sendiri:
Contoh kode
{
"image": {
"id": "waf_01kyb2m4xq7whs0d8n3prv6tez",
"url": "https://platform.bird.com/v1/whatsapp/messages/wam_01kya19eknftrs2s6p82asmvnh/media/waf_01kyb2m4xq7whs0d8n3prv6tez",
"mime_type": "image/jpeg",
"caption": "Is this the right part?"
}
}Ambil byte-nya dengan method media channel, dengan meneruskan message id dan id media:
const media = await bird.whatsapp.messages.media(
"wam_01kya19eknftrs2s6p82asmvnh",
"waf_01kyb2m4xq7whs0d8n3prv6tez",
);
console.log(media.contentType, media.contentLength);media = client.whatsapp.messages.media(
"wam_01kya19eknftrs2s6p82asmvnh", "waf_01kyb2m4xq7whs0d8n3prv6tez"
)
print(media.content_type, media.content_length)media, err := client.Whatsapp.Messages.Media(context.Background(),
"wam_01kya19eknftrs2s6p82asmvnh", "waf_01kyb2m4xq7whs0d8n3prv6tez")
if err != nil {
log.Fatal(err)
}
fmt.Println(media.ContentType, media.ContentLength)$media = $bird->whatsapp->messages->media('wam_01kya19eknftrs2s6p82asmvnh', 'waf_01kyb2m4xq7whs0d8n3prv6tez');
file_put_contents('photo.jpg', $media->data);
echo $media->contentType, ' ', $media->contentLength;bird whatsapp media <message-id> <media-id>curl -L -X GET "https://{region}.platform.bird.com/v1/whatsapp/messages/{message_id}/media/{media_id}" \
-H "Authorization: Bearer $TOKEN"Anda mendapatkan byte-nya kembali dengan mime_type storage yang dideklarasikan untuk file tersebut. ID yang tidak dikenali Bird mengembalikan 404, dan pesan keluar tidak memiliki media tersimpan untuk disajikan.
Pesan dapat dibaca kembali selama 30 hari setelah tiba, dan medianya tidak pernah bertahan lebih lama dari pesannya. Endpoint ini membaca pesan sebelum menyajikan file, jadi setelah jendela itu berlalu keduanya menjawab 404. Simpan file yang Anda butuhkan lebih lama selagi pesan masih dapat dibaca. Satu kasus yang berakhir lebih awal adalah jika byte yang tersimpan hilang sebelum jendela habis: fetch menjawab 410 E15021, dan pesan masih dapat dibaca kembali dengan mime_type dan caption media-nya.
Di balik layar, endpoint ini menjawab 302 dengan presigned URL yang berlaku selama 15 menit. SDK dan CLI menangani redirect itu untuk Anda. Jika Anda memanggilnya langsung, presigned URL membawa kredensialnya sendiri, sehingga request yang di-redirect tidak boleh mengirimkan header Authorization Anda juga. Mengirim keduanya akan gagal. curl -L menghapus header pada cross-host redirect secara otomatis; klien yang meneruskan header apa adanya perlu mengambil Location sebagai request terpisah tanpa autentikasi.
Balasan kutipan
in_reply_to_message_id menamai pesan yang dijawab oleh pesan masuk, saat WhatsApp menandainya sebagai balasan:
Contoh kode
{
"id": "wam_01kyb2m4xq7whs0d8n3prv6tez",
"direction": "inbound",
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"text": { "body": "Yes, that one" }
}WhatsApp tidak menandai setiap balasan, dan balasan yang tidak ditandai tidak membawa ID sama sekali. Field ini juga dihilangkan jika pesan yang dikutip tidak dapat dicocokkan dengan pesan yang disimpan Bird: pesan yang dikirim sebelum workspace ini mulai merekamnya, atau pesan yang sudah melewati 15 hari penyimpanan message id WhatsApp oleh Bird. Ketidakcocokan menghilangkan field tersebut alih-alih melaporkannya, yang terbaca sama seperti balasan yang tidak menjawab apa pun.
Perlakukan field ini sebagai petunjuk, bukan sebagai kunci. metadata pada pesan kirim Anda sendiri tidak membantu di sini, karena ia tetap pada pesan Anda dan tidak pernah berpindah ke balasan kontak, sehingga integrasi yang harus mengetahui pertanyaan mana yang dijawab perlu melacak sendiri pertanyaan terakhir yang dikirimkan ke kontak tersebut. Lihat Mengutip pesan untuk sisi pengiriman.
Webhook
Subscribe ke whatsapp.received untuk menindaklanjuti pesan masuk saat tiba, alih-alih mem-poll daftar. Payload membawa konten di atas event envelope, sehingga endpoint tidak perlu membaca ulang:
Contoh kode
{
"type": "whatsapp.received",
"timestamp": "2026-08-25T09:04:11.118Z",
"data": {
"whatsapp_id": "wam_01kyb2m4xq7whs0d8n3prv6tez",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
"direction": "inbound",
"from": { "phone_number": "+14155550100", "display_name": "Alex Rivera" },
"to": { "phone_number": "+13124495569" },
"in_reply_to_message_id": "wam_01kya19eknftrs2s6p82asmvnh",
"interactive_reply": {
"type": "button",
"button": { "slug": "cancel-booking", "text": "Cancel" }
},
"tags": null,
"metadata": null
}
}Lihat event WhatsApp untuk envelope lengkap dan daftar event selengkapnya.
Langkah selanjutnya
- Service message: sisi pengiriman dari content arm yang sama
- Mengirim pesan WhatsApp: membalas di dalam jendela layanan, dan mengutip pesan
- Event WhatsApp: daftar event lengkap, melalui API atau webhook
- Log WhatsApp: menelusuri percakapan di dashboard
Sumber daya terkait
Lanjutkan dengan dokumentasi, panduan, dan contoh untuk topik ini. Sumber daya tersedia dalam bahasa Inggris.
Tonton panduannyaConnecting WhatsApp to Bird: from buying a number to a live channelPahami konsepnyaWhat is the 24-hour customer service window on WhatsApp?Gunakan alatnyaWhatsApp message builderJelajahi kemampuannyaWhatsApp
Coba praktiknya dan dapatkan ringkasan implementasi