WhatsApp API Interactive Messages
Panduan lengkap WhatsApp API interactive messages. Buttons, lists, quick replies. Buat bot lebih interaktif. Tutorial developer!
Interactive = User experience lebih baik!
Interactive messages memungkinkan user klik tombol atau pilih dari list daripada ketik manual. Lebih mudah, lebih cepat, lebih sedikit error.
Jenis Interactive Messages
š± TIPE INTERACTIVE:
REPLY BUTTONS:
- Max 3 tombol
- User klik untuk reply
- Simple choices
LIST MESSAGE:
- Max 10 items (1 section)
- Max 10 sections
- Dropdown menu style
CTA BUTTONS:
- Call Phone Number
- Visit Website URL
LOCATION REQUEST:
- Minta user share lokasi
FLOW MESSAGE:
- Multi-step form
- Complex interactionsReply Buttons
Kirim Reply Buttons:
javascript
async function sendReplyButtons(to, bodyText, buttons) {
const url = `https://graph.facebook.com/v17.0/${PHONE_NUMBER_ID}/messages`;
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'interactive',
interactive: {
type: 'button',
header: {
type: 'text',
text: 'Pilih Opsi'
},
body: {
text: bodyText
},
footer: {
text: 'Klik tombol di bawah'
},
action: {
buttons: buttons.map((btn, i) => ({
type: 'reply',
reply: {
id: btn.id,
title: btn.title // Max 20 karakter
}
}))
}
}
};
return await axios.post(url, payload, {
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
}
// Usage
await sendReplyButtons(
'628123456789',
'Hai! Mau ngapain hari ini?',
[
{ id: 'btn_order', title: 'š Order' },
{ id: 'btn_track', title: 'š¦ Cek Pesanan' },
{ id: 'btn_help', title: 'š¬ Bantuan' }
]
);Handle Button Response:
javascript
// Di webhook handler
function handleInteractiveResponse(message) {
if (message.type !== 'interactive') return;
const interactive = message.interactive;
if (interactive.type === 'button_reply') {
const buttonId = interactive.button_reply.id;
const buttonTitle = interactive.button_reply.title;
console.log(`User klik: ${buttonTitle} (${buttonId})`);
switch (buttonId) {
case 'btn_order':
return handleOrder(message.from);
case 'btn_track':
return handleTracking(message.from);
case 'btn_help':
return handleHelp(message.from);
}
}
}List Message
Kirim List:
javascript
async function sendListMessage(to, bodyText, buttonText, sections) {
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'interactive',
interactive: {
type: 'list',
header: {
type: 'text',
text: 'Menu Utama'
},
body: {
text: bodyText
},
footer: {
text: 'Pilih dari menu'
},
action: {
button: buttonText, // Max 20 karakter
sections: sections
}
}
};
return await sendMessage(payload);
}
// Usage
await sendListMessage(
'628123456789',
'Selamat datang! Pilih kategori produk:',
'Lihat Kategori',
[
{
title: 'Produk',
rows: [
{
id: 'cat_fashion',
title: 'š Fashion',
description: 'Baju, celana, aksesoris'
},
{
id: 'cat_electronics',
title: 'š± Elektronik',
description: 'HP, laptop, gadget'
},
{
id: 'cat_food',
title: 'š Makanan',
description: 'Snack, minuman, frozen'
}
]
},
{
title: 'Layanan',
rows: [
{
id: 'svc_track',
title: 'š¦ Cek Pesanan',
description: 'Lacak status pengiriman'
},
{
id: 'svc_help',
title: 'š¬ Bantuan',
description: 'Chat dengan CS'
}
]
}
]
);Handle List Response:
javascript
function handleListResponse(message) {
if (message.interactive.type === 'list_reply') {
const selectedId = message.interactive.list_reply.id;
const selectedTitle = message.interactive.list_reply.title;
const selectedDescription = message.interactive.list_reply.description;
console.log(`User pilih: ${selectedTitle}`);
// Route berdasarkan selection
if (selectedId.startsWith('cat_')) {
return showCategoryProducts(message.from, selectedId);
}
if (selectedId.startsWith('svc_')) {
return handleService(message.from, selectedId);
}
}
}CTA Buttons (Call to Action)
Call Phone Number:
javascript
async function sendCallButton(to, bodyText, phoneNumber, buttonText) {
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'interactive',
interactive: {
type: 'cta_url',
body: {
text: bodyText
},
action: {
name: 'cta_url',
parameters: {
display_text: buttonText,
url: `tel:${phoneNumber}`
}
}
}
};
return await sendMessage(payload);
}
// Untuk call button di template, gunakan:
// type: 'PHONE_NUMBER' di template componentsVisit URL:
javascript
async function sendUrlButton(to, bodyText, url, buttonText) {
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'interactive',
interactive: {
type: 'cta_url',
body: {
text: bodyText
},
action: {
name: 'cta_url',
parameters: {
display_text: buttonText,
url: url
}
}
}
};
return await sendMessage(payload);
}
// Usage
await sendUrlButton(
'628123456789',
'Klik tombol di bawah untuk melihat produk lengkap!',
'https://shop.brand.com/catalog',
'š Lihat Katalog'
);Location Request
Minta Lokasi User:
javascript
async function requestLocation(to, bodyText) {
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'interactive',
interactive: {
type: 'location_request_message',
body: {
text: bodyText
},
action: {
name: 'send_location'
}
}
};
return await sendMessage(payload);
}
// Usage
await requestLocation(
'628123456789',
'Untuk cek ongkir, share lokasi kamu dengan klik tombol di bawah:'
);Handle Location Response:
javascript
function handleLocationMessage(message) {
if (message.type === 'location') {
const { latitude, longitude, name, address } = message.location;
console.log(`Location: ${latitude}, ${longitude}`);
console.log(`Name: ${name}`);
console.log(`Address: ${address}`);
// Calculate shipping, find nearest store, etc
return calculateShipping(latitude, longitude);
}
}Kombinasi dengan Media
Buttons dengan Image Header:
javascript
async function sendButtonsWithImage(to, imageUrl, bodyText, buttons) {
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'interactive',
interactive: {
type: 'button',
header: {
type: 'image',
image: {
link: imageUrl
}
},
body: {
text: bodyText
},
action: {
buttons: buttons.map(btn => ({
type: 'reply',
reply: { id: btn.id, title: btn.title }
}))
}
}
};
return await sendMessage(payload);
}
// Usage - Product dengan buttons
await sendButtonsWithImage(
'628123456789',
'https://brand.com/product.jpg',
'šļø Tas Kulit Premium\n\nš° Rp 500.000\nš¦ Ready stock',
[
{ id: 'buy_now', title: 'š Beli' },
{ id: 'add_cart', title: 'š + Keranjang' },
{ id: 'ask_cs', title: 'š¬ Tanya' }
]
);Unofficial API (Baileys)
Reply Buttons:
javascript
async function sendButtons(sock, to, text, buttons) {
const jid = `${to}@s.whatsapp.net`;
await sock.sendMessage(jid, {
text: text,
buttons: buttons.map(btn => ({
buttonId: btn.id,
buttonText: { displayText: btn.text },
type: 1
})),
headerType: 1
});
}
// Atau dengan template buttons
await sock.sendMessage(jid, {
templateButtons: [
{
index: 1,
urlButton: {
displayText: 'Kunjungi Website',
url: 'https://brand.com'
}
},
{
index: 2,
callButton: {
displayText: 'Hubungi Kami',
phoneNumber: '+628123456789'
}
},
{
index: 3,
quickReplyButton: {
displayText: 'Quick Reply',
id: 'quick_1'
}
}
],
text: 'Pilih opsi:'
});List Message:
javascript
async function sendList(sock, to, text, buttonText, sections) {
const jid = `${to}@s.whatsapp.net`;
await sock.sendMessage(jid, {
text: text,
buttonText: buttonText,
sections: sections,
listType: 1
});
}
// Usage
await sendList(sock, '628123456789', 'Pilih menu:', 'Menu', [
{
title: 'Kategori',
rows: [
{ title: 'Fashion', rowId: 'cat_fashion' },
{ title: 'Elektronik', rowId: 'cat_elec' }
]
}
]);Flow Builder Example
javascript
// Multi-step conversation flow
const flows = {
'start': {
message: 'Selamat datang! Mau ngapain?',
buttons: [
{ id: 'flow_order', title: 'Order' },
{ id: 'flow_track', title: 'Cek Pesanan' }
],
next: {
'flow_order': 'select_category',
'flow_track': 'input_order_id'
}
},
'select_category': {
type: 'list',
message: 'Pilih kategori:',
sections: [/* ... */],
next: {
'cat_*': 'show_products'
}
},
// ... more steps
};
async function handleFlowStep(phone, step, input) {
const currentFlow = flows[step];
const nextStep = currentFlow.next[input];
// Save user state
await saveUserState(phone, nextStep);
// Send next message
await sendFlowMessage(phone, flows[nextStep]);
}Best Practices
DO ā
- Gunakan buttons untuk pilihan terbatas
- Gunakan list untuk banyak pilihan
- ID yang descriptive
- Combine dengan media
- Handle semua responses
- Fallback untuk unknownDON'T ā
- Terlalu banyak buttons (max 3)
- Title terlalu panjang (max 20 char)
- Skip handling responses
- Tidak ada fallback
- Nested menus terlalu dalam
- Ignore user free textFAQ
Kapan pakai buttons vs list?
Buttons: 2-3 pilihan simple. List: lebih dari 3 atau perlu deskripsi.
Bisa combine buttons dan list?
Tidak dalam 1 message. Tapi bisa sequential - buttons dulu, lalu list.
Interactive di template bisa?
Ya! Bisa tambahkan buttons di template (Quick Reply atau CTA).
Kesimpulan
Interactive = Better UX!
| Text Only | Interactive |
|---|---|
| Harus ketik | Klik tombol |
| Typo prone | Error-free |
| Slow | Fast |
| Confusing | Clear options |