Skip to content

gusnips/wuzapi-node

Repository files navigation

WuzAPI Client

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.

πŸš€ Features

  • πŸ”₯ 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

πŸ“¦ Installation

npm install wuzapi

or

yarn add wuzapi

⚑ Quick Start

Basic Setup

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! πŸŽ‰",
});

Login Options

Option 1: QR Code (Traditional)

// Get QR code for scanning
const qr = await client.session.getQRCode();
console.log("Scan this QR code:", qr.QRCode);

Option 2: Phone Pairing (New!)

// Pair using phone number (generates verification code)
await client.session.pairPhone("5491155554444");

πŸ”§ Configuration

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" }
);

πŸ’¬ Essential Chat Operations

// 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
);

πŸ‘₯ Group Management

// 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

πŸ‘€ User Operations

// 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");

πŸ”— Webhook Setup

// 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
);

πŸ“š Examples

Check out the complete examples in the examples/ directory:

Run Examples

# 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

πŸ€– Simple Bot Example

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 });
});

πŸ“– Complete API Reference

πŸ“± Session Module - Connection and authentication

Connection

// 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();

Authentication

// 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);

S3 Storage

// 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

Basic 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]",
  },
});

Media Messages

// 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...",
});

Interactive Messages

// 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
);

Message Management

// 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",
});

Location and Contacts

// 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",
});

Media Download

// 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

Basic Group Operations

// 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]");

Group Settings

// 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'

Group Media

// 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]");

Invites and Participants

// 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,
]);

πŸ“‹ Complete Webhook Events List

WuzAPI supports 45 different webhook events. Here's the complete list:

πŸ”§ Connection & Session Events

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"

πŸ” Authentication Events

WebhookEventType.QR; // "QR"
WebhookEventType.QR_SCANNED_WITHOUT_MULTIDEVICE; // "QRScannedWithoutMultidevice"
WebhookEventType.PAIR_SUCCESS; // "PairSuccess"
WebhookEventType.PAIR_ERROR; // "PairError"

πŸ’¬ Message Events

WebhookEventType.MESSAGE; // "Message"
WebhookEventType.UNDECRYPTABLE_MESSAGE; // "UndecryptableMessage"
WebhookEventType.RECEIPT; // "Receipt"
WebhookEventType.MEDIA_RETRY; // "MediaRetry"

πŸ‘₯ Group Events

WebhookEventType.GROUP_INFO; // "GroupInfo"
WebhookEventType.JOINED_GROUP; // "JoinedGroup"

πŸ‘€ User & Contact Events

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"

🚫 Blocklist Events

WebhookEventType.BLOCKLIST; // "Blocklist"
WebhookEventType.BLOCKLIST_CHANGE; // "BlocklistChange"

πŸ“± App State & Sync Events

WebhookEventType.APP_STATE; // "AppState"
WebhookEventType.APP_STATE_SYNC_COMPLETE; // "AppStateSyncComplete"
WebhookEventType.HISTORY_SYNC; // "HistorySync"
WebhookEventType.OFFLINE_SYNC_COMPLETED; // "OfflineSyncCompleted"
WebhookEventType.OFFLINE_SYNC_PREVIEW; // "OfflineSyncPreview"

πŸ“ž Call Events

WebhookEventType.CALL_OFFER; // "CallOffer"
WebhookEventType.CALL_ACCEPT; // "CallAccept"
WebhookEventType.CALL_TERMINATE; // "CallTerminate"
WebhookEventType.CALL_OFFER_NOTICE; // "CallOfferNotice"
WebhookEventType.CALL_RELAY_LATENCY; // "CallRelayLatency"

πŸ“° Newsletter Events

WebhookEventType.NEWSLETTER_JOIN; // "NewsletterJoin"
WebhookEventType.NEWSLETTER_LEAVE; // "NewsletterLeave"
WebhookEventType.NEWSLETTER_MUTE_CHANGE; // "NewsletterMuteChange"
WebhookEventType.NEWSLETTER_LIVE_UPDATE; // "NewsletterLiveUpdate"

πŸ”§ System Events

WebhookEventType.CAT_REFRESH_ERROR; // "CATRefreshError"
WebhookEventType.FB_MESSAGE; // "FBMessage"

πŸ“¦ Webhook Payload Structure

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"
}

🎯 Event Subscription Examples

// 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}`);
});

🎣 Webhook Event Handling

WuzAPI sends real-time events to your webhook endpoint. Here's how to handle them:

πŸ†• Type-Safe Message Discovery

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");
}

🎯 Available Message Types

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
}

Basic Webhook Setup

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 });
  }
});

Message Types

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
}

πŸ› οΈ Advanced Topics

⚠️ 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);
  }
}

Common Error Codes

  • 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

🀝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# 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

πŸ“„ License

MIT License - see the LICENSE file for details.

πŸ”— Links


πŸ“Š Changelog

Latest Updates

  • βœ… 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.

About

TypeScript client library for WuzAPI WhatsApp API

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published