Lompat ke konten
20 min read

Menghubungkan perangkat lunak Anda ke WhatsApp

Terbitkan kunci API, petakan templat WhatsApp yang telah disetujui, arahkan webhook ke server Anda sendiri, dan panggil REST API — panduan lengkap untuk Manajemen API.

Menghubungkan perangkat lunak Anda ke WhatsApp

Manajemen API adalah cara sistem lain — perangkat lunak penagihan, toko online, atau backend Anda sendiri — mengirim pesan WhatsApp melalui WizMessage. Di sini Anda menerbitkan kunci API untuk sistem tersebut, menentukan templat WhatsApp yang telah disetujui mana yang boleh dikirimnya, dan mengarahkannya ke webhook agar balasan bisa kembali masuk. Panduan ini menelusuri seluruh alurnya, lalu mendokumentasikan REST API yang akan dipanggil oleh developer Anda.

Dasbor

Di mana kunci API Anda tersimpan

Setiap kunci yang telah Anda terbitkan muncul di sini pada bagian API Keys. Setiap baris menampilkan status kunci, prefiks publiknya (satu-satunya bagian dari kunci yang masih ditampilkan lagi setelah Anda membuatnya), dan berapa banyak panggilan yang telah dilakukannya hari ini. "Manage" membuka kunci tersebut; tombol alih menjedanya tanpa menghapusnya.

Panduan video — 2 langkah, 0:05. Pilih satu langkah untuk memutar bagian itu saja.
Dasbor API Keys yang menampilkan setiap kunci yang diterbitkan beserta status, prefiks publik, dan jumlah panggilan hariannya

Kunci yang belum selesai disiapkan

Kunci yang belum memiliki templat terpetakan akan menampilkan lencana "Needs setup". Kunci tersebut dapat melakukan autentikasi, tetapi tidak dapat mengirim pesan templat sampai Anda memetakan salah satunya — sehingga integrasi yang baru setengah dikonfigurasi langsung terlihat sekilas, alih-alih baru gagal nanti saat pengiriman.

Baris kunci API yang menampilkan lencana Needs setup karena belum ada templat yang dipetakan padanya

Penyiapan terpandu

Langkah 1 — Apa yang ingin Anda hubungkan?

"Connect your software" membuka wizard empat langkah. Mulailah dengan menamai kunci sesuai sistem yang akan menggunakannya, lalu pilih preset yang cocok. Preset hanya menyarankan nama field yang masuk akal — preset penagihan menyarankan invoice_number, amount, due_date, customer_name — preset tidak membatasi apa yang boleh Anda petakan.

Panduan video — 4 langkah, 0:19. Pilih satu langkah untuk memutar bagian itu saja.
Langkah 1 wizard, menamai kunci API dan memilih preset yang cocok dengan sistem yang dihubungkan

Langkah 2 — Pilih pesannya

Pilih salah satu templat WhatsApp Anda yang telah disetujui. Templat tersimpan di Meta, bukan di sini — daftar ini diambil secara langsung dari akun WhatsApp Anda yang terhubung, dan hanya templat berstatus APPROVED yang dapat dikirim. Langkah ini opsional: lewati saja jika kunci hanya akan mengirim teks biasa, lalu petakan templat di kemudian hari.

Langkah 2 wizard, memilih salah satu templat WhatsApp yang telah disetujui dan diambil langsung dari Meta

Langkah 3 — Ke mana balasan harus dikirim?

Ketika seseorang membalas pesan Anda, atau laporan pengiriman masuk kembali, kami mengirimkannya melalui POST ke URL yang Anda kendalikan. Biarkan nonaktif jika sistem Anda hanya mengirim. Anda dapat menambahkannya nanti dari tab Webhooks pada kunci tersebut — tidak ada yang bersifat permanen di sini.

Langkah 3 wizard, mengatur URL webhook tempat balasan dan laporan pengiriman dikirimkan

Langkah 4 — Mulai digunakan

Menekan Next pada langkah sebelumnya adalah yang sebenarnya membuat kunci — layar ini hanyalah konfirmasinya. Salin ketiga nilainya sekarang: kunci API, rahasia API, dan rahasia penanda tangan webhook hanya ditampilkan tepat satu kali dan tidak dapat dipulihkan setelahnya. Jika Anda kehilangan rahasianya, Anda harus merotasinya, yang berarti memperbarui sistem apa pun yang sedang menggunakannya.

Langkah 4 wizard, menampilkan kunci API, rahasia API, dan rahasia penanda tangan webhook tepat satu kali

Mengelola kunci

Ikhtisar

Membuka sebuah kunci akan membawa Anda ke tab Overview: apa saja yang boleh dilakukannya, seberapa berat penggunaannya, dan endpoint apa saja yang dapat dipanggilnya. Angka penggunaan dibaca dari log permintaan, sehingga mencerminkan trafik yang sebenarnya.

Panduan video — 1 langkah, 0:05.
Tab Overview sebuah kunci API yang menampilkan izin, penggunaan, dan endpoint yang dapat dipanggil

Kunci yang masih perlu disiapkan

Kunci yang belum memiliki templat terpetakan justru terbuka pada tab Setup — wizard yang sama, tersemat langsung di halaman. Perhatikan bahwa tab-nya berbeda dari tangkapan layar sebelumnya: selama sebuah kunci belum memiliki setidaknya satu templat, tab Templates dan Webhooks tidak ditampilkan, karena belum ada apa pun untuk dikerjakan.

Panduan video — 1 langkah, 0:05.
Kunci yang belum dikonfigurasi terbuka pada tab Setup, dengan tab Templates dan Webhooks yang belum ditampilkan

Templat

Setiap kartu mewakili satu templat yang boleh dikirim oleh kunci ini. Teks isinya adalah pesan sebagaimana disetujui di Meta, dan chip di bawahnya adalah nama variabel yang akan disuplai oleh sistem Anda. "Try it" mengirim pesan uji coba, "Get code" menghasilkan permintaan siap pakai dalam delapan bahasa.

Panduan video — 2 langkah, 0:07. Pilih satu langkah untuk memutar bagian itu saja.
Tab Templates, satu kartu per templat dengan teks isi yang telah disetujui dan chip nama variabel

Membaca variabel — satu hal yang layak dicermati pelan-pelan

Perhatikan kartu payment_failed_alert. Pesannya berjalan {{1}}, lalu {{3}}, lalu {{2}} — placeholder-nya TIDAK berurutan secara numerik di dalam teks. Chip di bawahnya justru diurutkan secara numerik: customer_name mengisi {{1}}, renewal_date mengisi {{2}}, plan_name mengisi {{3}}. Cocokkan nilai Anda dengan NOMOR-nya, jangan pernah dengan urutan kemunculan placeholder di dalam kalimat. Hal ini paling sering menjebak orang pada templat terjemahan, di mana susunan kata menggeser posisi placeholder.

Kartu templat yang placeholder-nya muncul tidak berurutan secara numerik di dalam isi pesan

Tiga tombol pada setiap templat

"Try it" — kirim uji coba tanpa menulis kode

Tombol pesawat kertas membuka templat ini dengan nilai contoh yang sudah terisi, satu untuk setiap nama variabel. Ini cara tercepat memastikan sebuah pemetaan sudah benar sebelum developer Anda menyentuhnya. Perhatikan tombol alihnya: "Simulate Only" adalah bawaannya dan tidak ada apa pun yang keluar — server hanya memantulkan payload Anda kembali. Ubah ke "Send Real Message" dan pesan WhatsApp sungguhan akan terkirim ke nomor di kotak tersebut, serta dikenai biaya.

Panduan video — 7 langkah, 0:21. Pilih satu langkah untuk memutar bagian itu saja.
Dialog Try it, terisi satu nilai contoh untuk setiap variabel beserta tombol alih Simulate Only

Apa yang dikembalikan oleh pengiriman tersimulasi

Menekan Send Request dalam mode Simulate Only mengembalikan permintaan persis seperti yang diterima platform, lengkap dengan status HTTP dan waktu pulang-pergi. Bacalah ini sebagai pemeriksaan bentuk, bukan gladi bersih: ini memastikan JSON Anda terbaca dan kunci Anda diterima, tetapi TIDAK memvalidasi nama variabel Anda terhadap pemetaan dan tidak pernah menghubungi Meta. Payload yang lolos simulasi tetap bisa ditolak saat dikirim sungguhan. Untuk membuktikan pemetaannya sendiri, aktifkan Send Real Message dan kirim ke ponsel Anda sendiri.

Respons pengiriman tersimulasi, memantulkan permintaan kembali beserta status HTTP dan waktu pulang-perginya

"Get code" — permintaan yang sudah dituliskan untuk Anda

Tombol tanda kurung siku menghasilkan permintaan yang siap jalan untuk templat ini dalam delapan bahasa: cURL, JavaScript, Node.js, Python, PHP, Ruby, Go, dan C#. Serahkan kepada siapa pun yang menulis integrasinya. Variabelnya muncul sebagai {{placeholders}} yang dinamai sesuai pemetaan Anda, dan kredensialnya dibiarkan sebagai YOUR_API_KEY / YOUR_API_SECRET — dialog ini tidak pernah mencetak kunci asli Anda, jadi cuplikannya aman ditempelkan ke sebuah tiket.

Dialog Get code yang menampilkan permintaan siap pakai untuk templat ini dengan kredensial placeholder

Mengganti bahasa

Klik bahasa mana pun di bagian atas dan cuplikannya ditulis ulang untuk bahasa itu — panggilan yang sama, header yang sama, klien HTTP milik bahasa tersebut. Setiap cuplikan dibuat saat pertama kali Anda mengekliknya, jadi jeda pemuatan singkat pada pergantian pertama adalah hal wajar. Copy mengambil cuplikan apa adanya: sudah lengkap, termasuk import-nya, dan jika kunci ini mewajibkan tanda tangan, langkah penandatanganannya pun sudah ada di dalamnya.

Permintaan yang sama ditulis ulang untuk bahasa lain setelah dipilih pada baris bahasa

"Edit" — ubah apa yang dikirim sistem Anda

Ikon pensil membuka pemetaannya sendiri. Maket ponsel di bagian atas adalah pesan sungguhan dengan nama Anda saat ini yang sudah disubstitusikan, sehingga Anda bisa melihat apa yang akan dibaca pelanggan. Di bawahnya, setiap variabel yang terdeteksi dapat diganti namanya, diurutkan ulang, ditandai wajib, atau diberi tipe — tanggal, nilai mata uang, gambar. Mengganti nama variabel juga menggantinya di payload API Anda, sehingga sistem yang masih mengirim nama lama akan mulai gagal: ubah keduanya bersamaan.

Dialog edit pemetaan dengan pratinjau ponsel di atas daftar variabel yang dapat diganti nama dan diurutkan ulang

Test API — alat yang sama, endpoint mana pun

"Test API" di bagian atas tab adalah "Try it" tanpa terkunci pada satu templat: pilih salah satu dari tiga endpoint pengiriman, ganti templat dari dropdown kedua, dan sunting body-nya sebebas Anda. Gunakan untuk memeriksa panggilan mentah /messages/text atau /messages/template, yang tidak punya kartu sendiri karena tidak terikat pada pemetaan mana pun. Perhatikan bahwa variabel templat ini masih bernama body_1, body_2, body_3 — begitulah rupa templat yang belum dipetakan, dan itulah yang hendak diperbaiki oleh "Edit".

Dialog Test API dengan dropdown endpoint, dropdown templat, dan body yang bebas disunting

Balasan

Webhook — menerima balasan kembali

Mengirim hanyalah separuh dari sebuah integrasi. Arahkan webhook ke endpoint HTTPS Anda sendiri dan WizMessage akan mengirimkan pesan masuk serta pembaruan pengiriman ke sana melalui POST. Rahasia penanda tangan hanya ditampilkan sekali saat dibuat; verifikasi pada setiap pengiriman agar Anda yakin panggilan tersebut benar-benar berasal dari kami.

Tab Webhooks, tempat endpoint HTTPS menerima pesan masuk dan pembaruan pengiriman

Peristiwa apa saja yang Anda terima

Centang peristiwa yang harus diterima endpoint ini. Masing-masing datang sebagai POST tersendiri.

PeristiwaKapan terpicu
message.receivedSeorang pelanggan mengirimi Anda pesan.
message.reactionSeseorang menambahkan atau menghapus reaksi emoji. Terpicu di kedua arah — lihat Reaksi.
message.sentSebuah pesan terkirim keluar — dari API, dari dasbor web, atau diketik di ponsel bisnis itu sendiri. data.source memberi tahu yang mana.
message.deliveredPesan sampai di perangkat penerima.
message.readPenerima membukanya.
message.failedPengiriman atau penyampaian gagal; data.error memuat alasannya.

Catatan: message.received dan message.reaction masuk hanya dikirim ketika sistem chatbot akun disetel ke Webhook. Jika disetel ke yang lain, pesan masuk justru menuju bot dan endpoint Anda tidak pernah dipanggil — tab Webhooks akan memperingatkan Anda saat kondisi ini berlaku. Reaksi yang dikirim bisnis itu sendiri (direction: "outbound") tidak terpengaruh oleh setelan ini.

Catatan: Reaksi yang dikirim bisnis dari ponselnya sendiri dulu datang sebagai message.sent dengan body "[Unsupported message type]". Sekarang datang sebagai message.reaction dengan direction: "outbound". Centang event baru itu jika Anda mengandalkannya.

Pengiriman bersifat at-least-once. Lakukan dedupe berdasarkan event bersama data.message_id, bukan hanya header X-Webhook-Id, dan balas 2xx dengan cepat.

Referensi REST API

Semua yang dijelaskan di atas mengonfigurasi kunci. Bagian ini adalah yang benar-benar dipanggil oleh developer Anda. Base URL-nya adalah https://wizmessage.com/api/v1/external. Setiap endpoint memerlukan header autentikasi di bawah ini dan tunduk pada batas kecepatan milik kunci tersebut.

Autentikasi

Kirim kunci API Anda pada setiap permintaan. Jika kunci mengaktifkan "Require signature", Anda juga harus menandatangani permintaan tersebut — dan kunci dengan opsi itu aktif akan langsung menolak panggilan apa pun yang tidak ditandatangani.

HeaderNilai
X-API-KeyKunci API Anda — nilai pk_live_… selengkapnya, bukan hanya prefiks yang ditampilkan di dasbor.
X-TimestampTimestamp Unix dalam detik. Ditolak jika selisihnya lebih dari 5 menit dari waktu server.
X-API-SignatureHMAC-SHA256 dari timestamp + "." + rawBody, dengan kunci SHA256(api_secret), hex huruf kecil.

Catatan: Tanda tangan hanya diwajibkan ketika kunci mengaktifkan require_signature. Jika tidak, kunci API saja sudah cukup untuk mengirim pesan — dan justru itulah sebabnya kunci ini adalah sebuah rahasia, bukan sekadar pengenal. Perlakukan seperti kata sandi: kunci ditampilkan sekali saja, dan siapa pun yang memegangnya dapat mengirim pesan ke pelanggan Anda.

const crypto = require('node:crypto')

const body = JSON.stringify({ to: '+919876543210', message: 'Hello' })
const timestamp = Math.floor(Date.now() / 1000).toString()

const secretHash = crypto.createHash('sha256').update(API_SECRET).digest('hex')
const signature = crypto.createHmac('sha256', secretHash)
	.update(timestamp + '.' + body)
	.digest('hex')

await fetch('https://wizmessage.com/api/v1/external/messages/text', {
	method: 'POST',
	headers: {
		'Content-Type': 'application/json',
		'X-API-Key': API_KEY,
		'X-Timestamp': timestamp,
		'X-API-Signature': signature,
	},
	body,
})

Endpoint

MethodPathTujuan
POST/messages/textMengirim pesan teks biasa. Hanya berfungsi di dalam jendela percakapan 24 jam yang masih terbuka.
POST/messages/mediaKirim dokumen, gambar, video, atau berkas audio. Hanya berfungsi di dalam jendela percakapan 24 jam yang terbuka.
POST/messages/reactionBereaksi pada sebuah pesan dengan emoji, atau hapus reaksi yang Anda kirim.
POST/messages/templateMengirim templat, dengan menyediakan sendiri array components mentah milik Meta.
POST/messages/template/sendMengirim templat menggunakan pemetaan yang Anda konfigurasikan di dasbor. Inilah yang sebaiknya Anda gunakan.
POST/messages/interactive/listMengirim pesan daftar interaktif.
POST/messages/interactive/buttonMengirim hingga tiga tombol balasan.
GET/messages/:uuidMemeriksa status pengiriman pesan yang telah Anda kirim.
POST/media/uploadMengunggah PDF/gambar/video ke Meta dan mendapatkan media_id untuk digunakan pada header templat.
GET/templatesMenampilkan daftar templat yang tersedia untuk kunci ini.
GET/templates/:nameMengambil detail satu templat.

Mengirim templat yang telah dipetakan

Inilah payload yang berpasangan dengan tab Templates. Anda mengirim variabel berdasarkan NAMA — nama yang ditampilkan sebagai chip pada kartu templat — dan platform yang menyusun components milik Meta untuk Anda. Itulah inti dari pemetaan templat: sistem penagihan Anda tidak perlu tahu apa pun tentang format component milik Meta.

POST /api/v1/external/messages/template/send

{
	"to": "+919876543210",
	"template_name": "payment_failed_alert",
	"language": "en",
	"variables": {
		"customer_name": "Priya Sharma",
		"renewal_date": "12 Aug 2026",
		"plan_name": "Wiz Pro"
	},
	"reference": "invoice-2026-0817"
}

Catatan: Nama variabel harus sama persis dengan pemetaannya — nama yang tidak dikenali akan diabaikan, dan nama wajib yang hilang akan ditolak dengan 400. reference sepenuhnya milik Anda: nilainya dikembalikan pada webhook sehingga Anda dapat mengaitkan laporan pengiriman dengan record di sistem Anda sendiri.

Batas kecepatan

Setiap kunci memiliki batasnya sendiri, yang terlihat pada tab Overview — secara default 60 permintaan/menit dan 1.000 pesan/hari. Respons menyertakan sisa kuota, jadi kurangi laju permintaan saat kuota menipis alih-alih terus mencoba ulang hingga membentur batas.

Mengirim berkas dengan API

Di dalam jendela 24 jam yang terbuka, perangkat lunak Anda dapat mengirim berkas secara langsung — tanpa template, tanpa persetujuan. Satu endpoint mencakup dokumen, gambar, video, dan audio.

Dua cara melampirkan berkas pada pesan mediaPOST /messages/medialinkURL publik yang kami teruskan ke WhatsAppdiambil ulang pada setiap pengirimancocok untuk berkas yang sudah Anda hostmedia_idunggah sekali, pakai ulang id-nyaberlaku 30 haricocok untuk berkas yang sering dikirimTautan harus dapat diakses publik — WhatsApp yang mengambilnya, bukan server Anda yang mengirimnya.
Setiap pengiriman media membawa tepat salah satunya. Jika keduanya dikirim, media_id yang dipakai.

Apa yang bisa Anda kirim

Type yang Anda sebut dalam permintaan menentukan batasannya. Yang lebih besar, atau berformat di luar daftar, ditolak sebelum sampai ke WhatsApp.

TipeFormatUkuran maks.CaptionNama berkas
documentpdf, doc, docx, xls, xlsx, ppt, pptx, txt100 MB
imagejpg, jpeg, png, webp5 MB
videomp4, 3gp16 MB
audioaac, amr, mp3, ogg, m4a16 MB
POST /api/v1/external/messages/media

{
	"to": "+919876543210",
	"type": "document",
	"link": "https://example.com/invoice-2026-0817.pdf",
	"filename": "Invoice 2026-0817.pdf",
	"caption": "Your invoice for August",
	"reference": "invoice-2026-0817"
}

Unggah sekali, kirim berkali-kali

Jika Anda mengirim berkas yang sama berulang kali — daftar harga, katalog, PDF ketentuan — unggah sekali dan simpan id-nya. Id tetap berlaku 30 hari dan menghemat WhatsApp mengambil ulang URL Anda di setiap pesan.

Mengunggah berkas sekali dan mengirimnya berulang kaliPOST /media/uploadberkasnya sendirimedia_idberlaku 30 hariPOST /messages/mediakirim sesering yang Anda mauTerkirimwebhook melaporkan hasilnya
Id dapat dipakai ulang sampai kedaluwarsa; hanya langkah pengiriman yang diulang.
POST /api/v1/external/messages/media

{
	"to": "+919876543210",
	"type": "image",
	"media_id": "1234567890",
	"caption": "This month’s catalogue"
}

Kapan pengiriman ditolak

  • Di luar jendela 24 jam. Media bebas memerlukan percakapan terbuka. Kirim template yang disetujui — lihat panduan kotak masuk bersama.
  • Kunci tidak punya send_media. Periksa chip izin di tab Overview kunci.
  • Caption pada audio. WhatsApp tidak menampilkannya, jadi ditolak alih-alih dibuang diam-diam.
  • Nama berkas pada selain dokumen. Hanya dokumen yang menampilkan nama.
  • Tidak ada media_id maupun link. Tepat satu diperlukan.

Catatan: Anda bisa mencoba semua ini tanpa menulis kode. Buka kunci, tekan Test API, lalu pilih POST /messages/media dari daftar endpoint — body-nya sudah terisi, dan "Get code" menuliskan permintaan yang sama dalam delapan bahasa.

Reaksi

Reaksi adalah emoji yang seseorang tempelkan pada satu pesan — 👍 pada konfirmasi pesanan, ❤️ pada sebuah foto. Ia bukan pesan tersendiri: ia menunjuk ke sebuah pesan. Perangkat lunak Anda bisa membaca reaksi begitu terjadi, dan mengirimkannya.

Satu event, tiga asal

Reaksi bisa datang dari pelanggan Anda, dari pemilik yang menekannya di ponsel aplikasi Business, atau dari perangkat lunak Anda sendiri lewat API. Ketiganya tiba pada event message.reaction yang sama, jadi satu handler mencakup semua kasus — direction dan source memberi tahu Anda yang mana.

Tiga asal sebuah reaksi dan field yang menandai masing-masingPelanggan Andabereaksi kepada Andadirection: inboundtanpa field sourcecontact menyebut siapaPonsel aplikasi Businesspemilik yang menekandirection: outboundsource: mobilePerangkat lunak AndaAnda memanggil APIdirection: outboundsource: apireference dikembalikanHanya reaksi masuk yang membawa data kontak — reaksi keluar berasal dari bisnis, yang sudah Anda kenal.
Satu event, tiga asal. Baca direction dulu, baru source.

Seperti apa webhook reaksi itu

Berikut seorang pelanggan menambahkan 👍 pada pesan yang Anda kirim kepadanya.

{
	"version": 1,
	"event": "message.reaction",
	"timestamp": "2026-08-01T09:14:22.031Z",
	"data": {
		"message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgSQjkz…",
		"direction": "inbound",
		"from": "+919876543210",
		"to": "+911122334455",
		"reaction": {
			"message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgUQ0Uz…",
			"emoji": "👍",
			"action": "added"
		},
		"contact": {
			"name": "Priya Sharma",
			"wa_id": "919876543210"
		}
	}
}

Ada dua message_id di payload itu dan keduanya bukan hal yang sama. Inilah field yang pantas dibaca dua kali.

FieldApa itu
data.message_idId reaksi itu sendiri — bukan pesan yang dikenai reaksi.
data.reaction.message_idwamid pesan yang dikenai reaksi. Inilah yang Anda cocokkan dengan catatan Anda sendiri.
data.reaction.emojiEmojinya. String kosong ketika reaksi dihapus.
data.reaction.actionadded atau removed. Diturunkan dari emoji, jadi Anda bisa langsung bercabang di sini.
data.directioninbound — pelanggan yang bereaksi. outbound — bisnis yang bereaksi.
data.sourceHanya untuk keluar: mobile (ponsel aplikasi Business) atau api (perangkat lunak Anda). Tidak ada pada yang masuk.
data.from / data.toRelatif terhadap arah, seperti message.sent: masuk berarti pelanggan → bisnis, keluar berarti bisnis → pelanggan.
data.referenceHanya pada reaksi yang dikirim perangkat lunak Anda sendiri, dan hanya jika Anda menyertakannya.
data.contact, data.user_id, data.usernameHanya yang masuk — siapa yang bereaksi. Tidak ada pada setiap reaksi keluar.

Catatan: data.from biasanya nomor telepon pelanggan, tetapi WhatsApp tidak selalu mengirimkannya. Jika tidak, Anda menerima id pengguna WhatsApp mereka — jadi perlakukan from sebagai pengenal, bukan sesuatu yang selalu bisa Anda hubungi.

Menambah dan menghapus reaksi

Menghapus reaksi adalah event tersendiri, dengan emoji kosong dan action: "removed".

{
	"event": "message.reaction",
	"data": {
		"message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgSN0U3…",
		"direction": "inbound",
		"reaction": {
			"message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgUQ0Uz…",
			"emoji": "",
			"action": "removed"
		}
	}
}

Setiap ketukan adalah pesan WhatsApp tersendiri dengan id sendiri. Bereaksi 👍, menggantinya jadi ❤️, lalu menghapusnya sama sekali menghasilkan tiga event, dan tidak ada yang menggantikan yang lain di penyimpanan Anda. Kunci pada data.reaction.message_id dan simpan yang terbaru — itulah reaksi pesan tersebut saat ini.

Mengirim reaksi dari perangkat lunak Anda

Endpoint yang sama menambah dan menghapus. Mana yang terjadi sepenuhnya bergantung pada apakah Anda mengirim emoji.

Bagaimana endpoint reaksi yang sama menambah dan menghapus reaksiPOST /messages/reactionsebuah emojiemoji yang ingin ditampilkansatu per orang per pesanmenambahkan reaksiemoji kosongmenghapus yang Anda kirim tadikirim field-nya, tapi kosongmenghapusnyaUntuk menghapus reaksi, kirim emoji sebagai string kosong. Menghilangkan field-nya akan ditolak.
Satu endpoint, dua hasil. Field emoji yang menentukan.
POST /api/v1/external/messages/reaction

{
	"to": "+919876543210",
	"message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgUQ0Uz…",
	"emoji": "👍",
	"reference": "invoice-2026-0817"
}

message_id di sini adalah id milik WhatsApp — whatsapp_message_id dari respons pengiriman, atau data.reaction.message_id dari sebuah webhook. Ia tidak pernah salah satu uuid kami. Reaksi memakai izin send_text, jadi kunci apa pun yang bisa mengirim pesan ke pelanggan bisa bereaksi.

Catatan: Reaksi tidak pernah menghasilkan message.delivered maupun message.read. WhatsApp tidak mengirimkannya untuk sebuah reaksi — satu-satunya event lanjutan yang mungkin adalah message.failed, ketika reaksi ditolak. Menelusurinya dengan GET /messages/:uuid berjalan seperti pengiriman lain.

Ketika sebuah reaksi ditolak

Sebagian penolakan terjadi di sini, sebelum apa pun sampai ke WhatsApp. Penolakan ini mengembalikan error ke panggilan API Anda dan tidak menghasilkan webhook sama sekali — tidak ada yang perlu dilaporkan, karena tidak ada yang dikirim.

  • Kunci tidak punya send_text. 403. Reaksi memakai ulang izin itu; tidak ada izin lain yang perlu diberikan.
  • to bukan format E.164. 422. Format +… yang sama seperti endpoint lain.
  • message_id hilang atau kosong. 422. Maksimal 255 karakter.
  • emoji hilang. 422. Untuk menghapus reaksi kirim "emoji": "" — kirim field-nya dalam keadaan kosong, jangan dihilangkan. Maksimal 16 karakter.

Sisanya terjadi di WhatsApp, setelah kami menerima panggilan Anda. Anda mendapat 200 dan webhook message.reaction lebih dulu, lalu message.failed dengan error 131009 begitu WhatsApp menolaknya.

  • Pesan berusia lebih dari 30 hari. Batas dari WhatsApp untuk bereaksi, bukan batas kami — kami tidak memeriksa usianya.
  • Pesan bukan bagian dari percakapan ini. wamid dari chat lain, atau salah satu uuid kami yang terkirim karena keliru.
  • Pesan sudah dihapus, atau ia sendiri sebuah reaksi. Anda tidak bisa bereaksi terhadap reaksi.

Catatan: Jika pengiriman langsung gagal alih-alih ditolak belakangan, Anda mendapat 500 dan message.failed yang data.message_id-nya adalah uuid kami, bukan wamid — tidak ada id WhatsApp untuk dilaporkan, karena WhatsApp tidak pernah menerimanya.

Catatan: Seperti endpoint lainnya, Anda bisa mencobanya tanpa menulis kode. Buka kunci, tekan Test API, lalu pilih POST /messages/reaction — bereaksilah pada sebuah pesan di ponsel Anda sendiri dan lihat webhook-nya tiba.