Builder for interactiveMessage.carouselMessage. Every card requires an image or video in its header and can carry its own native flow buttons.
- Each card has its own header, body, footer, and nativeFlowMessage.
- Header media is mandatory: an image or a video.
- A good fit for catalogs, recommendations, and visual choices.
Three products people often buy together. Swipe to see the rest.
Prices may change
Card structure
The library does not provide field-level helpers for cards. Build an object that follows theinteractiveMessage.carouselMessage.cards[] schema, then pass it to addCard().
| Field | Required | Description |
|---|---|---|
| header.hasMediaAttachment | Yes | Must be true. Without it, addCard() throws an error. |
| header.imageMessage / videoMessage | Yes* | Uploaded media or a Baileys media object. |
| body.text | No | Main card text. |
| footer.text | No | Footer text, usually a price or label. |
| nativeFlowMessage.buttons | No | Native flow buttons for this card. |
import { Carousel, Toolkit } from './lib/MessageBuilder.js';
const imageUrl = await Toolkit.toUrl(sock, imageBuffer, 'image');
const card = {
header: {
hasMediaAttachment: true,
imageMessage: { url: imageUrl },
},
body: { text: 'Arabica coffee 250g' },
footer: { text: '$12' },
nativeFlowMessage: {
buttons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Order',
id: 'arabica-coffee',
}),
},
],
},
};
await new Carousel(sock)
.setBody('Featured products')
.setFooter('Prices may change')
.addCard(card)
.send(jid);Methods
loadFrom
chainable.loadFrom(msg)Rebuilds the state from an existing interactiveMessage.carouselMessage.
Parameter
| Parameter | Type | Default | Description |
|---|---|---|---|
msgrequired | WAMessage | — | A message containing carouselMessage. |
thisaddCard
chainable.addCard(card)Adds one card or an array of cards. Every card must have header.hasMediaAttachment = true.
Parameter
| Parameter | Type | Default | Description |
|---|---|---|---|
cardrequired | object | Array<object> | — | A card with header, body, footer, and nativeFlowMessage following the Baileys schema. |
this- Throws Error("Card [index] must include an image or video in header") when header media is missing.
const card = {
header: {
hasMediaAttachment: true,
imageMessage: { url: 'https://example.com/product.jpg' },
},
body: { text: 'Arabica coffee 250g' },
footer: { text: '$12' },
nativeFlowMessage: {
buttons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({ display_text: 'Order', id: 'arabica-coffee' }),
},
],
},
};
await new Carousel(sock)
.setBody('Featured products')
.addCard(card)
.send(jid);build
.build(jid, options)Assembles the full carousel message. Unlike the other builders, this method is not async even though it returns the result of generateWAMessageFromContent.
Parameter
| Parameter | Type | Default | Description |
|---|---|---|---|
jidrequired | string | — | Destination JID. |
options.messageId | string | — | Custom message ID. |
WAMessagesend
async.send(jid, options)Builds and sends through relayMessage with the standard native flow node.
Parameter
| Parameter | Type | Default | Description |
|---|---|---|---|
jidrequired | string | — | Destination JID. |
options.messageId | string | — | Custom message ID. |
options.additionalNodes | Array | [] | Additional XMPP nodes. |
Promise<WAMessage>Notes
Media is not optional
A carousel without media is rejected before it is sent. If you need text-only cards, use AIRich or a Button list instead.
Media must be uploaded
ImageMessage.url should come from prepareWAMessageMedia or Toolkit.toUrl so WhatsApp servers can access it.