Install the whatsapp-business SDK
mainYou can install the SDK using npm or yarn to start interacting with the WhatsApp Business Cloud API.
npm install whatsapp-business
# or
yarn add whatsapp-businessrepository·main·Indexed 41 days ago
https://github.com/marcosnicolau/whatsapp-business-sdkA Node.js connector for the WhatsApp Business Cloud API with full TypeScript support. Version 1.14.3 provides a typed interface for sending messages (text, media, interactive, templates, and reactions), managing business profiles and phone numbers, handling webhooks, and monitoring account health status.
You can install the SDK using npm or yarn to start interacting with the WhatsApp Business Cloud API.
npm install whatsapp-business
# or
yarn add whatsapp-businessThe WebhookClient handles the subscription and setup for incoming WhatsApp webhooks. You must have an HTTPS connection and have configured your server URL in the Meta application management.
If you do not provide an existing Express app, the client will create a default one. You can specify a port and a path (which must match your application management settings).
You can provide your own Express application via the expressApp option. If you set shouldStartListening: false, you are responsible for calling app.listen() yourself.
Use initWebhook to define event handlers. Common handlers include onTextMessageReceived, which provides the message payload and the contact object.
import { WebhookClient, WABAClient } from "./index";
const webhookClient = new WebhookClient({
token: "<YOUR_VALIDATION_TOKEN>",
path: "/whatsapp/webhook",
port: 8080,
});
const wabaClient = new WABAClient({
accountId: "<ACCOUNT_ID>",
phoneId: "<PHONE_ID>",
apiToken: "<API_TOKEN>",
});
webhookClient.initWebhook({
onStartListening: () => {
console.log("Server started listening");
},
onTextMessageReceived: async (payload, contact) => {
try {
const messageId = payload.id.toString();
const contactNumber = contact.wa_id;
// Mark message as read
await wabaClient.markMessageAsRead(messageId);
// React to message
await wabaClient.sendMessage({
to: contactNumber,
type: "reaction",
reaction: { message_id: messageId, emoji: "😄" },
});
// Respond to message
await wabaClient.sendMessage({
type: "text",
to: contactNumber,
text: { body: "Ok!" },
// Optional: enables reply-to feature
context: {
message_id: messageId,
},
});
} catch (err) {
console.log(err);
}
},
});The SDK provides types to interpret the health status of your WhatsApp Business account. This status determines if you can send messages and provides context if limitations or blocks occur.
CanSendMessage)AVAILABLE: You can send messages normally.LIMITED: You can send messages, but there are restrictions. When in this state, the additional_info field in the entity will contain context about the limitation.BLOCKED: You cannot send messages. When in this state, the errors field in the entity will describe the reason and a possible solution.The overall health_status.can_send_message property is a rollup of all entities:
If you are integrating the SDK into an existing Express application, pass your app instance into the expressApp configuration object. Set shouldStartListening: false if you want to manage the server lifecycle (e.g., calling app.listen()) manually.
import { WebhookClient } from "./index";
import express from "express";
const myApp = express();
const webhookClient = new WebhookClient({
token: "<YOUR_VALIDATION_TOKEN>",
path: "/whatsapp/webhook",
expressApp: {
// Set to false if you want to initialize the server yourself
// Otherwise, it will start listening when firing initWebhook()
shouldStartListening: false,
app: myApp,
},
});
myApp.listen(8080, () => {
console.log("My server nows listens to whatsapp webhooks");
});To interact with the WhatsApp Business Cloud API, instantiate the WABAClient class. You must provide your account ID, API token, and business phone ID. Note that the accountId is obtained from the Meta developer app administration, not directly from the developer app itself.
Errors thrown by the client can be caught and cast to the WABAErrorAPI type to access the error message.
import { WABAClient, WABAErrorAPI } from "whatsapp-business";
const client = new WABAClient({
accountId: "<YOUR_ACCOUNT_ID>",
apiToken: "<YOUR_API_TOKEN>",
phoneId: "<YOUR_BUSINESS_PHONE_ID>",
});
const foo = async () => {
try {
const res = await client.getBusinessPhoneNumbers();
console.log(res);
} catch (err) {
const error: WABAErrorAPI = err;
console.error(error.message);
}
};
foo();Use the sendMessage method to send different types of media. The method accepts an object specifying the recipient (to), the message type, and the content payload.
type: "text" and provide a text object with a body string.type: "image" and provide an image object containing a link (URL) and an optional caption.// Sending a text message
const sendTextMessage = async (body: string, to: string) => {
try {
const res = await client.sendMessage({ to, type: "text", text: { body } });
console.log(res);
} catch (err) {
const error: WABAErrorAPI = err;
console.error(error.message);
}
};
// Sending an image message
const sendPictureMessage = async ({ link, caption }: MediaObject, to: string) => {
try {
const res = await client.sendMessage({ to, type: "image", image: { link, caption } });
console.log(res);
} catch (err) {
const error: WABAErrorAPI = err;
console.error(error.message);
}
};If you already have an Express server running, you can mount the WebhookClient router onto it instead of letting the client create a new application. This prevents port conflicts and allows you to use your existing middleware stack.
To do this, pass your application instance and set shouldStartListening: false.
import express from 'express';
import { WebhookClient } from 'whatsapp-business';
const app = express();
const client = new WebhookClient({
token: 'MY_SECRET_TOKEN',
path: '/whatsapp',
expressApp: {
app: app,
shouldStartListening: false
}
});
// This mounts the webhook router to the app at the specified path
client.initWebhook();
app.listen(3000, () => {
console.log('Server running on port 3000');
});The WebhookMessage type represents the core data received when a customer sends a message. Because the payload structure changes based on the type field, you should use type guards or check the type property before accessing specific fields.
Supported type values include:
text: Access content via text.body.image, video, document, audio: Access media metadata via image, video, document, or audio objects (containing id, mime_type, and optionally caption or filename).interactive: Contains user interactions like button_reply, list_reply, or nfm_reply (Native Flow Messages).location: Access via location object (latitude, longitude, address).contact: Access via contacts array.sticker: Access via sticker object.reaction: Access via reaction object.system: Triggered by profile or number updates.button, order, unknown, request_welcome.The SDK is exported from a single entrypoint. You can import the main client, all types, and webhook utilities directly from the package root. This includes WABA_client for interacting with the WhatsApp Business API and webhook-related classes for handling incoming events.
import { WABA_client, types, WebhookClient } from 'whatsapp-business-sdk';When sending audio, document, image, sticker, or video messages, you use a MediaObject. You can provide media in two ways:
https:// URL in the link field. You can optionally provide a provider string if the link requires additional configuration (like a bearer token).id field (obtained after uploading media to WhatsApp servers).Common MediaObject fields:
caption: Description for images, documents, or videos (not for audio/stickers).filename: Filename for documents (the extension determines the displayed format).link: The HTTP/HTTPS URL of the asset.id: The WhatsApp media ID.provider: Optional path/config for non-direct links.const imageMessage: Message = {
to: '1234567890',
type: 'image',
image: {
link: 'https://example.com/image.jpg',
caption: 'Check this out!'
}
};When setting up a webhook listener, use the WebhookEvents interface to define callbacks for different types of incoming data. The most common events are:
onMessageReceived: Fired for any incoming message. You must check the payload.type to differentiate between text, image, interactive, etc.onTextMessageReceived: A specialized callback that fires only when the message type is text.onStatusReceived: Fired when the status of a message you sent changes (e.g., sent, delivered, read, or failed).onError: Fired when a webhook error occurs.onStartListening: Fired when the server successfully starts listening for webhooks.const events: WebhookEvents = {
onMessageReceived: (payload, contact, metadata) => {
console.log(`New message from ${contact.wa_id}:`, payload.text?.body);
},
onStatusReceived: (status) => {
console.log(`Message ${status.id} status: ${status.status}`);
},
onError: (error) => {
console.error(`Webhook error: ${error.message}`);
}
};The Message type is the primary interface for sending various content types through the SDK. You must specify the to field (WhatsApp ID or phone number) and the type of message. Depending on the type, you must provide the corresponding payload object (e.g., text, image, template, interactive).
Supported MessageType values:
audio, contacts, document, image, interactive, location, sticker, template, text, video, reaction.Additional useful fields:
biz_opaque_callback_data: An arbitrary string (max 512 chars) used for tracking (e.g., template IDs). It is returned in webhook status updates.context: Used for the reply-to feature, requiring a message_id from a received webhook.recipient_type: Defaults to individual.import { Message } from 'whatsapp-business-sdk';
const message: Message = {
to: '1234567890',
type: 'text',
text: {
body: 'Hello, world!',
preview_url: true
},
biz_opaque_callback_data: 'my_custom_tracking_id'
};