A comprehensive TypeScript client library for the WuzAPI WhatsApp API. This library provides a simple and intuitive interface to interact with WhatsApp through the WuzAPI service.
- π₯ Full TypeScript Support - Complete type definitions for all API endpoints
- ποΈ Modular Architecture - Organized by functionality (admin, session, chat, user, group, webhook)
- π Promise-based - Modern async/await support
- π‘οΈ Error Handling - Comprehensive error handling with detailed error types
- π¦ Tree Shakable - Import only what you need
- π§ Easy Configuration - Simple setup with minimal configuration
- π Well Documented - Extensive documentation and examples
npm install wuzapi
or
yarn add wuzapi
import WuzapiClient from "wuzapi";
const client = new WuzapiClient({
apiUrl: "http://localhost:8080",
token: "your-user-token",
});
// Connect to WhatsApp
await client.session.connect({
Subscribe: ["Message", "ReadReceipt"],
Immediate: false,
});
// Send a message
await client.chat.sendText({
Phone: "5491155554444",
Body: "Hello from WuzAPI! π",
});
// Get QR code for scanning
const qr = await client.session.getQRCode();
console.log("Scan this QR code:", qr.QRCode);
// Pair using phone number (generates verification code)
await client.session.pairPhone("5491155554444");
interface WuzapiConfig {
apiUrl: string; // Your WuzAPI server URL
token?: string; // Authentication token (can be provided per request)
}
// Global token approach
const client = new WuzapiClient({
apiUrl: "http://localhost:8080",
token: "your-token",
});
// Flexible token approach
const client = new WuzapiClient({
apiUrl: "http://localhost:8080",
});
// Use different tokens for different operations
await client.chat.sendText(
{ Phone: "123", Body: "Hello" },
{ token: "user-specific-token" }
);
// Send text message
await client.chat.sendText({
Phone: "5491155554444",
Body: "Hello World!",
});
// Send image
await client.chat.sendImage({
Phone: "5491155554444",
Image: "data:image/jpeg;base64,/9j/4AAQ...",
Caption: "Check this out!",
});
// Send interactive buttons
await client.chat.sendButtons({
Phone: "5491155554444",
Body: "Choose an option:",
Buttons: [
{ ButtonId: "yes", ButtonText: { DisplayText: "Yes" }, Type: 1 },
{ ButtonId: "no", ButtonText: { DisplayText: "No" }, Type: 1 },
],
});
// Send list menu
await client.chat.sendList(
"5491155554444", // Phone
"View Menu", // Button text
"Select from menu:", // Description
"Options", // Top text/title
[
{
// Sections
Title: "Main Options",
Rows: [
{ Title: "Option 1", Desc: "First choice", RowId: "opt1" },
{ Title: "Option 2", Desc: "Second choice", RowId: "opt2" },
],
},
]
);
// Send poll (for groups only)
await client.chat.sendPoll(
"[email protected]", // Group JID
"What's your favorite color?", // Header
["Red", "Blue", "Green"] // Options array
);
// Create group
const group = await client.group.create("My Group", [
"5491155553934",
"5491155553935",
]);
// Get group info
const info = await client.group.getInfo(group.JID);
// Add participants
await client.group.updateParticipants(group.JID, "add", ["5491155553936"]);
// Set group settings
await client.group.setName(group.JID, "New Group Name");
await client.group.setTopic(group.JID, "Welcome message");
await client.group.setAnnounce(group.JID, true); // Only admins can send
// Check if numbers are WhatsApp users
const check = await client.user.check(["5491155554444"]);
// Get user info
const info = await client.user.getInfo(["5491155554444"]);
// Get contacts
const contacts = await client.user.getContacts();
// Send presence status
await client.user.sendPresence("available");
// Set webhook URL with events
await client.webhook.setWebhook("https://your-server.com/webhook", [
"Message",
"ReadReceipt",
]);
// Get webhook config
const config = await client.webhook.getWebhook();
// Update webhook with new URL, events, and status
await client.webhook.updateWebhook(
"https://new-server.com/webhook",
["Message", "ReadReceipt"],
true
);
Check out the complete examples in the examples/
directory:
- basic-usage.js - Getting started, connection, basic operations
- advanced-features.js - Phone pairing, interactive messages, advanced group management
- chatbot-example.js - Complete bot with commands and auto-replies
- webhook-events-example.js - Comprehensive webhook event handling
- webhook-types-example.js - β NEW! Complete webhook types with message discovery utilities
# Basic usage
node examples/basic-usage.js
# Advanced features
node examples/advanced-features.js
# Start chatbot
node examples/chatbot-example.js
# Webhook types example (with complete type safety)
node examples/webhook-types-example.js
import WuzapiClient from "wuzapi";
const client = new WuzapiClient({
apiUrl: "http://localhost:8080",
token: "your-token",
});
// Connect and wait for messages
await client.session.connect({ Subscribe: ["Message"] });
await client.webhook.setWebhook("https://your-server.com/webhook", ["Message"]);
// In your webhook handler:
app.post("/webhook", async (req, res) => {
const webhookPayload = req.body;
// Validate payload structure
if (webhookPayload.token !== "your-expected-token") {
return res.status(401).json({ error: "Invalid token" });
}
// Handle by event type
switch (webhookPayload.type) {
case "Message":
const { event } = webhookPayload;
if (event.Message?.conversation) {
const message = event.Message.conversation;
const from = event.Info.RemoteJid.replace("@s.whatsapp.net", "");
if (message.toLowerCase().includes("hello")) {
await client.chat.sendText({
Phone: from,
Body: "Hello! π How can I help you?",
});
}
}
break;
case "Connected":
console.log("β
WhatsApp connected");
break;
case "QR":
console.log("π± QR Code:", webhookPayload.event.Codes);
break;
}
res.json({ success: true });
});
π± Session Module - Connection and authentication
// Connect to WhatsApp
await client.session.connect({
Subscribe: ["Message", "ReadReceipt", "HistorySync"],
Immediate: false,
});
// Get connection status
const status = await client.session.getStatus();
// Disconnect (keeps session)
await client.session.disconnect();
// Logout (destroys session)
await client.session.logout();
// Get QR code for scanning
const qr = await client.session.getQRCode();
// Pair phone using phone number (generates verification code)
await client.session.pairPhone("5491155554444");
// Request message history sync
await client.session.requestHistory();
// Configure proxy
await client.session.setProxy("socks5://user:pass@proxy:port", true);
// Configure S3 storage
await client.session.configureS3({
enabled: true,
endpoint: "https://s3.amazonaws.com",
region: "us-east-1",
bucket: "my-bucket",
accessKey: "AKIAIOSFODNN7EXAMPLE",
secretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
pathStyle: false,
mediaDelivery: "both",
retentionDays: 30,
});
// Get S3 configuration
const s3Config = await client.session.getS3Config();
// Test S3 connection
await client.session.testS3();
// Delete S3 configuration
await client.session.deleteS3Config();
π¬ Chat Module - Send and manage messages
// Send text message
await client.chat.sendText({
Phone: "5491155554444",
Body: "Hello World!",
Id: "optional-message-id",
});
// Reply to a message
await client.chat.sendText({
Phone: "5491155554444",
Body: "This is a reply",
ContextInfo: {
StanzaId: "original-message-id",
Participant: "[email protected]",
},
});
// Send image
await client.chat.sendImage({
Phone: "5491155554444",
Image: "data:image/jpeg;base64,/9j/4AAQ...",
Caption: "Check this out!",
});
// Send audio
await client.chat.sendAudio({
Phone: "5491155554444",
Audio: "data:audio/ogg;base64,T2dnUw...",
});
// Send video
await client.chat.sendVideo({
Phone: "5491155554444",
Video: "data:video/mp4;base64,AAAAIGZ0eXA...",
Caption: "Video caption",
});
// Send document
await client.chat.sendDocument({
Phone: "5491155554444",
Document: "data:application/pdf;base64,JVBERi0x...",
FileName: "document.pdf",
});
// Send sticker
await client.chat.sendSticker({
Phone: "5491155554444",
Sticker: "data:image/webp;base64,UklGRuI...",
});
// Send buttons
await client.chat.sendButtons({
Phone: "5491155554444",
Body: "Choose an option:",
Footer: "Select one:",
Buttons: [
{ ButtonId: "option1", ButtonText: { DisplayText: "Option 1" }, Type: 1 },
{ ButtonId: "option2", ButtonText: { DisplayText: "Option 2" }, Type: 1 },
],
});
// Send list message
await client.chat.sendList(
"5491155554444", // Phone
"View Menu", // Button text
"Please select from the menu:", // Description
"Menu Options", // Top text/title
[
{
// Sections
Title: "Main Course",
Rows: [
{ Title: "Pizza", Desc: "Delicious pizza", RowId: "pizza" },
{ Title: "Burger", Desc: "Tasty burger", RowId: "burger" },
],
},
]
);
// Send poll (for groups only)
await client.chat.sendPoll(
"[email protected]", // Group JID
"What's your favorite color?", // Header
["Red", "Blue", "Green"] // Options array
);
// Delete a message
await client.chat.deleteMessage("message-id-to-delete");
// Edit a message
await client.chat.editMessage(
"message-id-to-edit",
"5491155554444",
"This is the updated message text"
);
// React to message
await client.chat.react({
Phone: "5491155554444",
Body: "β€οΈ",
Id: "message-id-to-react-to",
});
// Mark messages as read
await client.chat.markRead({
Id: ["message-id-1", "message-id-2"],
Chat: "[email protected]",
});
// Send chat presence (typing indicator)
await client.chat.sendPresence({
Phone: "5491155554444",
State: "composing", // or "paused"
Media: "text",
});
// Send location
await client.chat.sendLocation({
Phone: "5491155554444",
Latitude: 48.85837,
Longitude: 2.294481,
Name: "Eiffel Tower, Paris",
});
// Send contact
await client.chat.sendContact({
Phone: "5491155554444",
Name: "John Doe",
Vcard:
"BEGIN:VCARD\nVERSION:3.0\nN:Doe;John;;;\nFN:John Doe\nTEL:+1234567890\nEND:VCARD",
});
// Download media
const media = await client.chat.downloadImage({
Url: "https://mmg.whatsapp.net/d/f/...",
MediaKey: "media-key...",
Mimetype: "image/jpeg",
FileSHA256: "file-hash...",
FileLength: 2039,
});
π€ User Module - User information and contacts
// Check if numbers are WhatsApp users
const check = await client.user.check(["5491155554444", "5491155554445"]);
// Get user information
const info = await client.user.getInfo(["5491155554444"]);
// Get user avatar
const avatar = await client.user.getAvatar("5491155554444", true); // true for preview
// Get all contacts
const contacts = await client.user.getContacts();
// Send user presence (online/offline status)
await client.user.sendPresence("available"); // or "unavailable"
π₯ Group Module - Group management
// List all groups
const groups = await client.group.list();
// Create a group
const newGroup = await client.group.create("My New Group", [
"5491155553934",
"5491155553935",
]);
// Get group info
const groupInfo = await client.group.getInfo("[email protected]");
// Leave a group
await client.group.leave("[email protected]");
// Set group name
await client.group.setName("[email protected]", "New Group Name");
// Set group topic/description
await client.group.setTopic(
"[email protected]",
"Welcome to our group! Please read the rules."
);
// Set group announcement setting (only admins can send messages)
await client.group.setAnnounce("[email protected]", true);
// Set group locked (only admins can modify info)
await client.group.setLocked("[email protected]", true);
// Set disappearing messages
await client.group.setEphemeral("[email protected]", "24h"); // '24h', '7d', '90d', or 'off'
// Set group photo (JPEG only)
await client.group.setPhoto(
"[email protected]",
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
);
// Remove group photo
await client.group.removePhoto("[email protected]");
// Get invite link
const invite = await client.group.getInviteLink("[email protected]");
// Join a group using invite link
const joinResult = await client.group.join(
"https://chat.whatsapp.com/XXXXXXXXX"
);
// Get group invite information
const inviteInfo = await client.group.getInviteInfo(
"https://chat.whatsapp.com/XXXXXXXXX"
);
// Update group participants (add, remove, promote, demote)
await client.group.updateParticipants(
"[email protected]",
"add", // "add", "remove", "promote", "demote"
["5491155553936", "5491155553937"]
);
π¨βπΌ Admin Module - User management (requires admin token)
// List all users
const users = await client.admin.listUsers({ token: "admin-token" });
// Add new user
const newUser = await client.admin.addUser(
{
name: "John Doe",
token: "user-token-123",
webhook: "https://example.com/webhook",
events: "Message,ReadReceipt", // optional
proxyConfig: {
enabled: true,
proxyURL: "socks5://user:pass@proxy:port",
},
s3Config: {
enabled: true,
endpoint: "https://s3.amazonaws.com",
region: "us-east-1",
bucket: "user-media-bucket",
accessKey: "AKIA...",
secretKey: "secret...",
pathStyle: false,
mediaDelivery: "both",
retentionDays: 30,
},
},
{ token: "admin-token" }
);
// Delete user by ID (ID is a string)
await client.admin.deleteUser("user-id-string", { token: "admin-token" });
// Delete user completely (full deletion including all data)
await client.admin.deleteUserComplete("user-id-string", {
token: "admin-token",
});
π Webhook Module - Webhook configuration
// Set webhook URL with specific events
await client.webhook.setWebhook("https://my-server.com/webhook", [
"Message",
"Receipt",
"Connected",
"Disconnected",
]);
// Get current webhook configuration
const webhookConfig = await client.webhook.getWebhook();
console.log("Webhook URL:", webhookConfig.webhook);
console.log("Subscribed events:", webhookConfig.subscribe);
// Update webhook URL, events, and status
await client.webhook.updateWebhook(
"https://my-new-server.com/webhook",
["Message", "Receipt", "Presence"],
true
);
// Delete webhook configuration
await client.webhook.deleteWebhook();
// Get all available events
const availableEvents = client.webhook.constructor.getAvailableEvents();
console.log("Available events:", availableEvents);
// Use the enum for type safety (TypeScript)
import { WebhookEventType } from "wuzapi";
await client.webhook.setWebhook("https://my-server.com/webhook", [
WebhookEventType.MESSAGE,
WebhookEventType.RECEIPT,
WebhookEventType.CONNECTED,
]);
WuzAPI supports 45 different webhook events. Here's the complete list:
WebhookEventType.CONNECTED; // "Connected"
WebhookEventType.DISCONNECTED; // "Disconnected"
WebhookEventType.CONNECT_FAILURE; // "ConnectFailure"
WebhookEventType.LOGGED_OUT; // "LoggedOut"
WebhookEventType.KEEP_ALIVE_RESTORED; // "KeepAliveRestored"
WebhookEventType.KEEP_ALIVE_TIMEOUT; // "KeepAliveTimeout"
WebhookEventType.CLIENT_OUTDATED; // "ClientOutdated"
WebhookEventType.TEMPORARY_BAN; // "TemporaryBan"
WebhookEventType.STREAM_ERROR; // "StreamError"
WebhookEventType.STREAM_REPLACED; // "StreamReplaced"
WebhookEventType.QR; // "QR"
WebhookEventType.QR_SCANNED_WITHOUT_MULTIDEVICE; // "QRScannedWithoutMultidevice"
WebhookEventType.PAIR_SUCCESS; // "PairSuccess"
WebhookEventType.PAIR_ERROR; // "PairError"
WebhookEventType.MESSAGE; // "Message"
WebhookEventType.UNDECRYPTABLE_MESSAGE; // "UndecryptableMessage"
WebhookEventType.RECEIPT; // "Receipt"
WebhookEventType.MEDIA_RETRY; // "MediaRetry"
WebhookEventType.GROUP_INFO; // "GroupInfo"
WebhookEventType.JOINED_GROUP; // "JoinedGroup"
WebhookEventType.PICTURE; // "Picture"
WebhookEventType.USER_ABOUT; // "UserAbout"
WebhookEventType.PUSH_NAME_SETTING; // "PushNameSetting"
WebhookEventType.PRIVACY_SETTINGS; // "PrivacySettings"
WebhookEventType.PRESENCE; // "Presence"
WebhookEventType.CHAT_PRESENCE; // "ChatPresence"
WebhookEventType.IDENTITY_CHANGE; // "IdentityChange"
WebhookEventType.BLOCKLIST; // "Blocklist"
WebhookEventType.BLOCKLIST_CHANGE; // "BlocklistChange"
WebhookEventType.APP_STATE; // "AppState"
WebhookEventType.APP_STATE_SYNC_COMPLETE; // "AppStateSyncComplete"
WebhookEventType.HISTORY_SYNC; // "HistorySync"
WebhookEventType.OFFLINE_SYNC_COMPLETED; // "OfflineSyncCompleted"
WebhookEventType.OFFLINE_SYNC_PREVIEW; // "OfflineSyncPreview"
WebhookEventType.CALL_OFFER; // "CallOffer"
WebhookEventType.CALL_ACCEPT; // "CallAccept"
WebhookEventType.CALL_TERMINATE; // "CallTerminate"
WebhookEventType.CALL_OFFER_NOTICE; // "CallOfferNotice"
WebhookEventType.CALL_RELAY_LATENCY; // "CallRelayLatency"
WebhookEventType.NEWSLETTER_JOIN; // "NewsletterJoin"
WebhookEventType.NEWSLETTER_LEAVE; // "NewsletterLeave"
WebhookEventType.NEWSLETTER_MUTE_CHANGE; // "NewsletterMuteChange"
WebhookEventType.NEWSLETTER_LIVE_UPDATE; // "NewsletterLiveUpdate"
WebhookEventType.CAT_REFRESH_ERROR; // "CATRefreshError"
WebhookEventType.FB_MESSAGE; // "FBMessage"
All webhook payloads follow this structure:
{
"event": { /* Event-specific data */ },
"type": "Message", // Event type from the list above
"token": "YOUR_TOKEN", // Your authentication token
// Optional media fields (when media is involved)
"s3": {
"url": "https://bucket.s3.amazonaws.com/media/file.jpg",
"key": "media/file.jpg",
"bucket": "your-bucket",
"size": 1024000,
"mimeType": "image/jpeg",
"fileName": "file.jpg"
},
"base64": "data:image/jpeg;base64,/9j/4AAQ...",
"mimeType": "image/jpeg",
"fileName": "image.jpg"
}
// Subscribe to all message-related events
await client.webhook.setWebhook("https://your-server.com/webhook", [
"Message",
"UndecryptableMessage",
"Receipt",
"MediaRetry",
]);
// Subscribe to connection events only
await client.webhook.setWebhook("https://your-server.com/webhook", [
"Connected",
"Disconnected",
"LoggedOut",
"QR",
]);
// Subscribe to group events
await client.webhook.setWebhook("https://your-server.com/webhook", [
"GroupInfo",
"JoinedGroup",
]);
// Subscribe to all events
await client.webhook.setWebhook("https://your-server.com/webhook", ["All"]);
// TypeScript: Use enum for type safety
import { WebhookEventType } from "wuzapi";
await client.webhook.setWebhook("https://your-server.com/webhook", [
WebhookEventType.MESSAGE,
WebhookEventType.RECEIPT,
WebhookEventType.CONNECTED,
WebhookEventType.QR,
]);
π° Newsletter Module - Newsletter management (Business accounts only)
// List all subscribed newsletters
const newsletters = await client.newsletter.list();
newsletters.Newsletters.forEach((newsletter) => {
console.log(`Newsletter: ${newsletter.Name}`);
console.log(`Description: ${newsletter.Description}`);
console.log(`Handle: ${newsletter.Handle}`);
console.log(`State: ${newsletter.State}`);
});
WuzAPI sends real-time events to your webhook endpoint. Here's how to handle them:
The library now includes comprehensive TypeScript types and utilities for handling webhook messages:
import WuzapiClient, {
discoverMessageType,
MessageType,
hasS3Media,
hasBase64Media,
} from "wuzapi";
// Discover message type automatically
const messageType = discoverMessageType(webhookPayload.event.Message);
switch (messageType) {
case MessageType.TEXT:
console.log("Text:", webhookPayload.event.Message.conversation);
break;
case MessageType.EXTENDED_TEXT:
console.log("Text:", webhookPayload.event.Message.extendedTextMessage.text);
break;
case MessageType.IMAGE:
const imageMsg = webhookPayload.event.Message.imageMessage;
console.log("Image:", imageMsg.mimetype, imageMsg.fileLength);
break;
case MessageType.VIDEO:
const videoMsg = webhookPayload.event.Message.videoMessage;
console.log("Video:", `${videoMsg.seconds}s`, videoMsg.caption);
break;
case MessageType.AUDIO:
const audioMsg = webhookPayload.event.Message.audioMessage;
console.log(audioMsg.ptt ? "Voice message" : "Audio file");
break;
case MessageType.DOCUMENT:
const docMsg = webhookPayload.event.Message.documentMessage;
console.log("Document:", docMsg.fileName, `${docMsg.pageCount} pages`);
break;
case MessageType.CONTACT:
const contactMsg = webhookPayload.event.Message.contactMessage;
console.log("Contact:", contactMsg.displayName);
break;
case MessageType.LOCATION:
const locationMsg = webhookPayload.event.Message.locationMessage;
console.log(
"Location:",
locationMsg.degreesLatitude,
locationMsg.degreesLongitude
);
break;
case MessageType.STICKER:
const stickerMsg = webhookPayload.event.Message.stickerMessage;
console.log(
"Sticker:",
stickerMsg.isAnimated ? "Animated" : "Static",
stickerMsg.mimetype
);
break;
case MessageType.REACTION:
const reactionMsg = webhookPayload.event.Message.reactionMessage;
console.log(
"Reaction:",
reactionMsg.text,
"to message",
reactionMsg.key.ID
);
break;
case MessageType.POLL_CREATION:
const pollMsg = webhookPayload.event.Message.pollCreationMessageV3;
console.log("Poll:", pollMsg.name, `${pollMsg.options.length} options`);
break;
case MessageType.BUTTONS_RESPONSE:
const buttonResponse = webhookPayload.event.Message.buttonsResponseMessage;
console.log("Button clicked:", buttonResponse.selectedButtonId);
break;
case MessageType.LIST_RESPONSE:
const listResponse = webhookPayload.event.Message.listResponseMessage;
console.log(
"List item selected:",
listResponse.singleSelectReply.selectedRowId
);
break;
case MessageType.GROUP_INVITE:
const groupInvite = webhookPayload.event.Message.groupInviteMessage;
console.log("Group invite:", groupInvite.groupName);
break;
case MessageType.VIEW_ONCE:
const viewOnceMsg = webhookPayload.event.Message.viewOnceMessage;
console.log("View once message received");
break;
// Handle other new message types
case MessageType.BUTTONS:
case MessageType.LIST:
case MessageType.TEMPLATE:
case MessageType.POLL:
case MessageType.POLL_UPDATE:
console.log(`Interactive message type: ${messageType}`);
break;
}
// Handle media intelligently
if (hasS3Media(webhookPayload)) {
console.log("S3 URL:", webhookPayload.s3.url);
} else if (hasBase64Media(webhookPayload)) {
console.log("Base64 media available");
}
enum MessageType {
// Basic messages
TEXT = "conversation", // Simple text messages
EXTENDED_TEXT = "extendedTextMessage", // Rich text messages
// Media messages
IMAGE = "imageMessage", // Photos, screenshots
VIDEO = "videoMessage", // Video files, GIFs
AUDIO = "audioMessage", // Audio files, voice messages
DOCUMENT = "documentMessage", // PDFs, Word docs, etc.
STICKER = "stickerMessage", // Stickers (animated/static)
// Contact & location
CONTACT = "contactMessage", // Shared contacts
LOCATION = "locationMessage", // Location pins
// Interactive messages
BUTTONS = "buttonsMessage", // Interactive buttons
LIST = "listMessage", // List menus
TEMPLATE = "templateMessage", // Template messages
// Response messages
BUTTONS_RESPONSE = "buttonsResponseMessage", // Button click responses
LIST_RESPONSE = "listResponseMessage", // List selection responses
// Group messages
GROUP_INVITE = "groupInviteMessage", // Group invitations
// Poll messages
POLL = "pollCreationMessage", // Polls (standard)
POLL_CREATION = "pollCreationMessageV3", // Polls (v3)
POLL_UPDATE = "pollUpdateMessage", // Poll vote updates
// Special messages
VIEW_ONCE = "viewOnceMessage", // View once messages
REACTION = "reactionMessage", // Message reactions (emoji)
EDITED = "editedMessage", // Edited messages
// System messages
PROTOCOL = "protocolMessage", // System messages
DEVICE_SENT = "deviceSentMessage", // Multi-device messages
UNKNOWN = "unknown", // Unrecognized types
}
import express from "express";
import WuzapiClient, { getMessageContent, hasS3Media } from "wuzapi";
const app = express();
app.use(express.json());
const client = new WuzapiClient({
apiUrl: "http://localhost:8080",
token: "your-token",
});
app.post("/webhook", async (req, res) => {
try {
const webhookPayload = req.body;
// Validate payload structure with token and type
if (
!webhookPayload.token ||
!webhookPayload.type ||
!webhookPayload.event
) {
return res
.status(400)
.json({ error: "Invalid webhook payload structure" });
}
// Verify token (optional security check)
if (webhookPayload.token !== "your-expected-token") {
return res.status(401).json({ error: "Invalid webhook token" });
}
console.log(`Received webhook event: ${webhookPayload.type}`);
// Handle S3 media if present
if (hasS3Media(webhookPayload)) {
console.log("S3 Media:", webhookPayload.s3.url);
}
const event = webhookPayload.event;
// Handle different event types
switch (webhookPayload.type) {
case "Message":
if (event.Message && event.Info) {
const messageContent = getMessageContent(event.Message);
const from = event.Info.RemoteJid.replace("@s.whatsapp.net", "");
if (messageContent?.type === "text") {
console.log(`Message from ${from}: ${messageContent.content}`);
// Auto-reply
if (messageContent.content.toLowerCase().includes("hello")) {
await client.chat.sendText({
Phone: from,
Body: "Hello! π How can I help you?",
});
}
}
}
break;
case "Receipt":
console.log("Message receipt:", event.Type, event.MessageIDs);
break;
case "Connected":
console.log("β
WhatsApp connected successfully");
break;
case "Disconnected":
console.log("β WhatsApp disconnected");
break;
case "QR":
console.log("π± QR Code received:", event.Codes);
break;
case "GroupInfo":
console.log("π₯ Group info updated:", event.GroupName);
break;
case "Presence":
console.log(
"π€ User presence:",
event.From,
event.Unavailable ? "offline" : "online"
);
break;
// Handle all other webhook events
default:
console.log(`Unhandled event type: ${webhookPayload.type}`, event);
}
res.json({ success: true });
} catch (error) {
console.error("Webhook error:", error);
res.status(500).json({ error: error.message });
}
});
The getMessageContent()
utility function returns structured message data:
const messageContent = getMessageContent(event.Message);
switch (messageContent?.type) {
case "text":
console.log("Text:", messageContent.content);
break;
case "image":
console.log("Image:", messageContent.content.caption);
break;
case "buttonsResponse":
console.log("Button clicked:", messageContent.content.selectedButtonId);
break;
case "listResponse":
console.log(
"List selection:",
messageContent.content.singleSelectReply?.selectedRowId
);
break;
// ... handle other types
}
β οΈ Error Handling
import { WuzapiError } from "wuzapi";
try {
await client.chat.sendText({
Phone: "invalid-number",
Body: "This will fail",
});
} catch (error) {
if (error instanceof WuzapiError) {
console.error("WuzAPI Error:", {
code: error.code,
message: error.message,
details: error.details,
});
} else {
console.error("Unexpected error:", error);
}
}
- 401: Authentication required
- 404: Endpoint not found
- 500: Server error
π§ Custom Configuration
// Custom axios configuration
import { BaseClient } from "wuzapi";
class CustomClient extends BaseClient {
constructor(config) {
super(config);
// Add custom interceptors
this.axios.interceptors.request.use((config) => {
console.log("Making request:", config.url);
return config;
});
}
}
π TypeScript Support
import {
WuzapiClient,
SendTextRequest,
SendMessageResponse,
GroupInfo,
User,
} from "wuzapi";
// All API requests and responses are fully typed
const request: SendTextRequest = {
Phone: "5491155554444",
Body: "Typed message",
};
const response: SendMessageResponse = await client.chat.sendText(request);
π Legacy Aliases
// These are equivalent:
await client.user.check(["5491155554444"]);
await client.users.check(["5491155554444"]); // Alias
await client.chat.sendText({ Phone: "123", Body: "Hi" });
await client.message.sendText({ Phone: "123", Body: "Hi" }); // Alias
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
# Clone the repository
git clone https://github.com/gusnips/wuzapi-node.git
cd wuzapi
# Install dependencies
npm install
# Run linter
npm run lint
# Build the project
npm run build
MIT License - see the LICENSE file for details.
- π WuzAPI Documentation
- π Issue Tracker
- π¬ Discussions
- β Phone Pairing: Alternative to QR code login
- β Interactive Messages: Buttons, lists, and polls
- β Message Management: Edit and delete messages
- β Advanced Groups: Full participant management
- β Newsletter Support: Business newsletter features
- β Enhanced Webhooks: Update and delete webhook configs
- β Proxy Support: Configure proxy for connections
- β History Sync: Request message history after login
Made with β€οΈ for the WhatsApp automation community.