Skip to main content
The Bot class is the main entry point for creating and managing WhatsApp bot instances. It extends Node.js EventEmitter and handles authentication, connection management, message routing, and middleware execution.

Import

import { Bot } from 'wapi';

Constructor

Creates a new Bot instance with authentication and account configuration.
new Bot(uuid: UUID, auth: IBotAuth, account: IBotAccount, logger?: Logger)
uuid
UUID
required
Unique identifier for the bot instance (from node:crypto)
auth
IBotAuth
required
Authentication handler implementing the IBotAuth interface:
account
IBotAccount
required
Account information object:
logger
Logger
Optional custom logger instance. If not provided, a default logger is created.

Example

import { Bot } from 'wapi';
import { randomUUID } from 'node:crypto';

const bot = new Bot(
  randomUUID(),
  authHandler,
  { jid: '', pn: '', name: '' }
);

Properties

uuid
UUID
Unique identifier for this bot instance
ws
BotWASocket | null
The Baileys WebSocket connection instance. Null when disconnected.
auth
IBotAuth
Authentication handler for managing credentials
account
IBotAccount
Current account information (updated after successful login)
status
BotStatus
Current connection status: "close", "open", or "reconnecting"
logger
Logger
Logger instance for debugging and monitoring
ping
number
Last message send latency in milliseconds (updated after each sendMessage call)
prefix
string
default:"!/"
Command prefix characters. Default is "!/" allowing both ! and / as prefixes.

Methods

use()

Registers global middleware functions that run for all incoming messages.
bot.use(...middlewares: MiddlewareFn[]): void
middlewares
MiddlewareFn[]
required
One or more middleware functions with signature:
(ctx: Context, next: () => Promise<void>) => Promise<void>
bot.use(async (ctx, next) => {
  console.log(`Received: ${ctx.text}`);
  await next();
});

command()

Registers command-specific middleware that only runs when a command is invoked.
bot.command(name: string, ...middlewares: MiddlewareFn[]): void
name
string
required
Command name (without prefix). Must be at least 1 character long.
middlewares
MiddlewareFn[]
required
Middleware functions to execute for this command
bot.command('hello', async (ctx) => {
  await ctx.reply('Hello! 👋');
});
Command names are case-insensitive and automatically converted to lowercase.

login()

Initiates the WhatsApp connection using QR code or OTP authentication.
await bot.login(method: "qr" | "otp"): Promise<void>
method
'qr' | 'otp'
required
Authentication method:
  • "qr": Generates QR codes for scanning (emits qr event)
  • "otp": Sends one-time password to phone number (emits otp event)
import qrcode from 'qrcode-terminal';

bot.on('qr', (qr) => {
  qrcode.generate(qr, { small: true });
  console.log('Scan the QR code above');
});

bot.on('open', (account) => {
  console.log(`Logged in as ${account.name}`);
});

await bot.login('qr');
For OTP login, the account.pn must be set with a valid phone number before calling login().

disconnect()

Gracefully disconnects the bot from WhatsApp.
await bot.disconnect(reason?: Error): Promise<void>
reason
Error
Optional error describing the disconnect reason. Defaults to “Intentional disconnection.”
// Graceful disconnect
await bot.disconnect();

// Disconnect with reason
await bot.disconnect(new Error('Maintenance mode'));

logout()

Logs out from WhatsApp and clears authentication data.
await bot.logout(reason?: Boom): Promise<void>
reason
Boom
Optional Boom error with logout reason
import { Boom } from '@hapi/boom';

await bot.logout(new Boom('User requested logout'));
After logout, you’ll need to authenticate again using QR code or OTP.

parseMentions()

Extracts WhatsApp mentions from text.
bot.parseMentions(text: string, server: JidServer): string[]
text
string
required
Text containing mentions in format @1234567890
server
JidServer
required
JID server type: "s.whatsapp.net" (phone numbers) or "lid" (LID format)
returns
string[]
Array of formatted JIDs
const text = 'Hello @1234567890 and @9876543210';
const mentions = bot.parseMentions(text, 's.whatsapp.net');
// Returns: ['1234567890@s.whatsapp.net', '9876543210@s.whatsapp.net']
Extracts URLs, emails, and phone numbers from text.
bot.parseLinks(text: string): string[]
text
string
required
Text to parse for links
returns
string[]
Array of extracted links (URLs, emails, phone numbers)
const text = 'Visit https://example.com or email test@example.com';
const links = bot.parseLinks(text);
// Returns: ['https://example.com', 'mailto:test@example.com']

sendMessage()

Sends a message to a WhatsApp chat.
await bot.sendMessage(
  jid: string,
  content: AnyMessageContent,
  options?: IBotSendMessageOptions
): Promise<Context | null>
jid
string
required
Recipient JID (chat ID)
content
AnyMessageContent
required
Message content object from Baileys:
options
IBotSendMessageOptions
Send options:
returns
Promise<Context | null>
Context object for the sent message, or null if sending failed
const ctx = await bot.sendMessage(
  '1234567890@s.whatsapp.net',
  { text: 'Hello World!' }
);
The ping property is automatically updated with send latency after each call.

groupMetadata()

Retrieves metadata for a group chat.
await bot.groupMetadata(jid: string): Promise<GroupMetadata | null>
jid
string
required
Group JID (must end with @g.us)
returns
Promise<GroupMetadata | null>
Group metadata object containing:
  • id: Group JID
  • subject: Group name
  • owner: Creator JID
  • creation: Creation timestamp
  • desc: Group description
  • participants: Array of participant objects
  • announce: Admin-only posting mode
  • restrict: Restrict group info changes
const metadata = await bot.groupMetadata('123456789@g.us');
if (metadata) {
  console.log(`Group: ${metadata.subject}`);
  console.log(`Members: ${metadata.participants.length}`);
  console.log(`Created: ${new Date(metadata.creation * 1000)}`);
}
Results are cached automatically to reduce API calls.

profilePictureUrl()

Gets the profile picture URL for a user or group.
await bot.profilePictureUrl(jid: string): Promise<string>
jid
string
required
User or group JID
returns
Promise<string>
Profile picture URL. Returns a default placeholder if no picture is set or on error.
const avatarUrl = await bot.profilePictureUrl(ctx.from.jid);
await ctx.replyWithImage(
  avatarUrl,
  { caption: 'Your profile picture' }
);

Events

The Bot class emits the following events:

qr

Emitted when a QR code is generated during login.
bot.on('qr', (qr: string) => {
  // Display QR code for scanning
  console.log(qr);
});
qr
string
QR code data string (can be rendered with qrcode libraries)

otp

Emitted when an OTP code is generated.
bot.on('otp', (code: string) => {
  // Display OTP code to user
  console.log(`Your code: ${code}`);
});
code
string
6-digit OTP code

open

Emitted when connection is successfully established.
bot.on('open', (account: IBotAccount) => {
  console.log(`Connected as ${account.name}`);
  console.log(`JID: ${account.jid}`);
  console.log(`Phone: ${account.pn}`);
});
account
IBotAccount
Updated account information with JID, phone number, and name

close

Emitted when connection is closed.
bot.on('close', (reason: string) => {
  console.log(`Disconnected: ${reason}`);
});
reason
string
Human-readable disconnect reason (includes status code and error message)

error

Emitted when an error occurs.
bot.on('error', (error: Error) => {
  console.error('Bot error:', error);
});
error
Error
Error object describing what went wrong
Always handle the error event to prevent unhandled promise rejections.

Complete Example

import { Bot } from 'wapi';
import { randomUUID } from 'node:crypto';
import qrcode from 'qrcode-terminal';

// Create bot instance
const bot = new Bot(
  randomUUID(),
  authHandler,
  { jid: '', pn: '', name: '' }
);

// Set custom prefix
bot.prefix = '!/';

// Global middleware
bot.use(async (ctx, next) => {
  console.log(`Message from ${ctx.from.name}: ${ctx.text}`);
  await next();
});

// Register commands
bot.command('ping', async (ctx) => {
  await ctx.reply(`🏓 Pong! (${bot.ping.toFixed(0)}ms)`);
});

bot.command('help', async (ctx) => {
  await ctx.reply(`
Available commands:
• !ping - Check bot latency
• !help - Show this message
  `.trim());
});

bot.command('groups', async (ctx) => {
  if (ctx.chat.type !== 'group') {
    await ctx.reply('❌ This command only works in groups');
    return;
  }
  
  const metadata = await bot.groupMetadata(ctx.chat.jid);
  if (!metadata) {
    await ctx.reply('❌ Failed to get group info');
    return;
  }
  
  await ctx.reply(`
Group: ${metadata.subject}
Members: ${metadata.participants.length}
Created: ${new Date(metadata.creation * 1000).toLocaleDateString()}
  `.trim());
});

// Event handlers
bot.on('qr', (qr) => {
  qrcode.generate(qr, { small: true });
});

bot.on('open', (account) => {
  console.log(`✅ Logged in as ${account.name}`);
});

bot.on('close', (reason) => {
  console.log(`❌ Disconnected: ${reason}`);
});

bot.on('error', (error) => {
  console.error('Error:', error);
});

// Start bot
await bot.login('qr');

See Also

Context

Learn about the Context object passed to middleware

Message Builder

Build formatted messages easily

Build docs developers (and LLMs) love