This guide assumes you already have a connected Baileys socket. If not, complete Installation first.
1. Send a quick reply
import { Button } from './lib/MessageBuilder.js';
const jid = '[email protected]';
await new Button(sock)
.setTitle('Hello!')
.setBody('How can we help?')
.setFooter('Reply with one of the options')
.addReply('Browse products', 'products')
.addReply('Contact support', 'support')
.send(jid);
The result is an interactiveMessage with two quick reply buttons. When a user taps one, WhatsApp sends back a reply containing that button’s id.
2. Handle the response
sock.ev.on('messages.upsert', async ({ messages, type }) => {
if (type !== 'notify') return;
for (const msg of messages) {
if (!msg.message || msg.key.fromMe) continue;
const text =
msg.message.conversation ||
msg.message.extendedTextMessage?.text;
const replyId =
msg.message.buttonsResponseMessage?.selectedButtonId ||
msg.message.listResponseMessage?.singleSelectReply?.selectedRowId ||
msg.message.templateButtonReplyMessage?.selectedId;
console.log({ text, replyId });
}
});
replyId is the id you passed to addReply() or makeRow().
3. Add a header image
await new Button(sock)
.setImage('https://example.com/banner.jpg', { caption: 'New menu' })
.setBody('Seasonal coffee is now available.')
.addUrl('View menu', 'https://example.com/menu', true)
.send(jid);
setImage() accepts a URL or a Buffer. Baileys uploads the media during build().
4. Build a nested list
await new Button(sock)
.setBody('Choose a category.')
.addSelection('Open menu')
.makeSection('Food')
.makeRow('Fried rice', '$8', 'Spice level adjustable', 'fried-rice')
.makeRow('Chicken noodles', '$7', 'Large portion', 'chicken-noodles')
.makeSection('Drinks')
.makeRow('Iced palm sugar latte', '$6', 'House blend', 'iced-latte')
.send(jid);
Order matters here: addSelection() → makeSection() → makeRow(). Calling makeRow() without an active section throws an error.
5. Inspect before sending
const msg = await new Button(sock)
.setBody('Hello')
.addReply('OK', 'ok')
.build(jid);
console.dir(msg.message, { depth: null });
Use build() when you want to inspect the payload, store a draft, or deliver through a custom path. send() calls build() and then relayMessage().
Common failure points
- Wrong JID — use
[email protected], not+62. - Socket not connected — media uploads and
relayMessage()will fail. - Buttons do not appear — check the
biz > interactive > native_flownode.send()adds it automatically, but custom delivery paths might not. - Media 403 — the URL must be reachable by WhatsApp servers, or use
resolveUrl: true. - Too many buttons — switch to
single_selector split the options across multiple messages.
Next steps
- Learn the fluent chaining pattern.
- Understand the build & send lifecycle.
- Try the playground to explore button variations.