WhatsApp API
npm install innovators-bot2A powerful WhatsApp client library that provides seamless integration between Baileys and WhatsApp-web.js style APIs. This library makes it easy to create WhatsApp bots and automation tools with a familiar interface.
- š Easy to use, familiar WhatsApp-web.js style API
- š± Multi-device support (Baileys v7.x.x)
- š¬ Send and receive messages
- ļæ½ Message reactions (add/remove emoji reactions)
- ļæ½šø Media handling (images, videos, documents)
- š„ Group management
- š¾ Message history and chat management
- š Auto-reconnect functionality
- š Read receipts
- š LID (Local Identifier) support for enhanced privacy
- šļø Signal repository store for LID/PN mapping
``bash`
npm install innovators-bot2
`javascript
const { WhatsAppClient } = require('innovators-bot2')
const qrcode = require('qrcode-terminal')
// Create client instance
const client = new WhatsAppClient({ sessionName: ".Sessions" });
// Handle QR Code
client.on('qr', qr => {
qrcode.generate(qr, { small: true })
})
// Handle ready event
client.on('connected', () => {
console.log('Client is ready!')
})
// Connect to WhatsApp
client.connect()
`Quick Start With Pairing code
`javascript
const { WhatsAppClient } = require('innovators-bot2')
const qrcode = require('qrcode-terminal')
const config = require('./config.json');
// Get authmethod from config file (default to 'qr' if not specified)
const authMethod = (config.whatsapp && config.whatsapp.authMethod) || 'qr';
const client = new WhatsAppClient({
sessionName: ".Sessions",
authmethod: authMethod
});
// Handle ready event
client.on('connected', () => {
console.log('Client is ready!')
})
// Connect to WhatsApp
client.connect()
`
`javascript
// Send a text message
await client.sendMessage('1234567890@s.whatsapp.net', 'Hello world!')
// Send a reply
await client.reply('1234567890@s.whatsapp.net', 'This is a reply', {
quoted: originalMessage
})
// Send with mentions
await client.sendMessage('1234567890@s.whatsapp.net', {
type: 'text',
text: 'Hey @user!',
mentions: ['user@s.whatsapp.net']
})
`
`javascript
// Send an image
await client.sendMedia('1234567890@s.whatsapp.net', './image.jpg', {
caption: 'Check out this image!'
})
// Send a document
await client.sendDocument('1234567890@s.whatsapp.net', './document.pdf',
'Check out this document!'
)
`
Create stickers easily from any image buffer with automatic conversion and metadata support.
`javascript
const fs = require('fs');
// Send a sticker from an image or video buffer
const buffer = fs.readFileSync('./image.jpg');
await client.sendSticker('1234567890@s.whatsapp.net', buffer, {
packName: 'Innovators',
author: 'Innovators Bot',
type: 'full', // 'full' or 'crop'
quality: 50
});
`
The library includes a built-in Anti-Delete system that tracks deleted messages in real-time.
`javascriptUser ${data.jid} deleted a message!
// Listen for deleted messages
client.on('message-deleted', async (data) => {
console.log();`
// Content of the deleted message
const original = data.originalMessage;
// Reply to the chat with the deleted content
await client.sendMessage(data.jid, 'I saw that! š', {
quoted: original
});
});
`javascript
// Get all groups
const groups = await client.getAllGroups()
// Add participant to group
// Note: If adding fails due to user's privacy settings (403),
// an invitation link is automatically sent to the user instead.
const result = await client.changeGroupParticipants(groupId, ['1234567890@s.whatsapp.net'], 'add')
if (result[0].status === 403 && result[0].invitationSent) {
console.log('User has privacy settings enabled. Invitation link sent!')
}
// Send a manual group invitation link
await client.sendGroupInvitation(groupId, '1234567890@s.whatsapp.net', 'Join my group!')
// Remove participant
await client.changeGroupParticipants(groupId, ['1234567890@s.whatsapp.net'], 'remove')
// Promote to admin
await client.changeGroupParticipants(groupId, ['1234567890@s.whatsapp.net'], 'promote')
// Demote admin
await client.changeGroupParticipants(groupId, ['1234567890@s.whatsapp.net'], 'demote')
`
#### Buttons
`javascript`
// Send interactive buttons
await client.sendButtons('1234567890@s.whatsapp.net', {
text: 'Do you like this bot?',
title: 'Feedback',
subtitle: 'Let us know!',
footer: 'Powered by Baileys',
interactiveButtons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'ā
Yes',
id: 'text_yes'
})
},
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'ā No',
id: 'text_no'
})
}
]
});
#### List Messages
`javascript`
// Send interactive list
await client.SendList('1234567890@s.whatsapp.net', {
text: 'Please select an option:',
title: 'Main Menu',
buttonText: 'View Options',
footer: 'Scroll to see more options',
sections: [
{
title: 'Account',
rows: [
{ title: 'Profile', id: 'profile', description: 'View your profile' },
{ title: 'Settings', id: 'settings', description: 'Account settings' }
]
},
{
title: 'Help',
rows: [
{ title: 'Support', id: 'support', description: 'Contact support' },
{ title: 'About', id: 'about', description: 'About this bot' }
]
}
]
});
`javascript
// Get chat history
const messages = await client.loadMessages(chatId, 50)
// Get specific message
const message = await client.loadMessage(chatId, messageId)
`
For a complete working example with message handling, group management, and error handling, check out our example.js file. This example includes:
- š Connection handling and QR code generation
- šØ Message handling with commands
- š„ Group management examples
- ā” Event listeners for various scenarios
- š ļø Error handling and logging
Feel free to use this example as a starting point for your WhatsApp bot implementation.
The library includes example bot commands that you can use:
- Check if bot is alive
- !echo - Echo back your text
- !help - Show all available commands$3
- !mention - Mention you in a message
- !reply - Reply to your message
- !react - React to your message with ā¤ļø
- !read - Mark messages as read
- !typing - Show typing indicator
- !presence - Set online presence$3
- !media - Send an example image
- !doc - Send an example document
- !location - Send a location
- !contact - Send a contact card$3
- !groups - List all your groups
- !add - Add participant to group
- !remove - Remove participant from group
- !promote - Promote participant to admin
- !demote - Demote admin to participant
- !list - Show interactive list message$3
- !buttons - Show interactive buttons
- !list - Display a scrollable list
- !logout - Logout from current session$3
- Anti-Delete - Automatically tracks and emits events for deleted messages$3
- !lid - Get your LID (Local Identifier)
- !pn - Get phone number from a LID
- !parse - Parse detailed JID information
- !normalize - Normalize a number to JID format$3
- !sticker - Create a sticker from an image$3
`javascript
// When QR code is generated
client.on('qr', qr => {
qrcode.generate(qr, { small: true })
})// When connection is established
client.on('connected', () => {
console.log('Client is ready!')
})
// When connection is in progress
client.on('connecting', (message) => {
console.log('Connection status:', message)
})
// When disconnected
client.on('disconnected', (error) => {
console.log('Client disconnected:', error)
})
`$3
`javascript
// When a new message is received
client.on('message', async msg => {
console.log('Message from:', msg.from)
console.log('Message content:', msg.body)
// Mark message as read
await client.readMessage(msg.raw.key)
// Handle different message types
if (msg.hasMedia) {
console.log('Message contains media')
// Handle media message
}
})
`$3
Listen for when users add or remove reactions (emojis) from messages:
`javascript
// When a message receives a reaction
client.on('message-reaction', async (reaction) => {
console.log('Reaction received!')
console.log('Chat:', reaction.from)
console.log('Sender:', reaction.sender)
console.log('Emoji:', reaction.emoji)
console.log('Is removed:', reaction.isRemoved)
// Check if reaction was added or removed
if (reaction.isRemoved) {
console.log('User removed their reaction')
} else {
console.log(User reacted with: ${reaction.emoji})
}
// Access the message key that was reacted to
console.log('Message ID:', reaction.messageKey.id)
// For group messages, get the participant who reacted
if (reaction.from.endsWith('@g.us')) {
console.log('Participant who reacted:', reaction.sender)
}
})
`#### Reaction Event Data Structure
The
message-reaction event provides the following data:| Property | Type | Description |
|----------|------|-------------|
|
from | string | Chat JID where the reaction occurred (prefers PN over LID) |
| sender | string | JID of the user who reacted (in groups, this is the participant) |
| participant | string\|null | Original participant JID (could be LID or PN) |
| participantAlt | string\|null | Alternate participant JID format |
| emoji | string\|null | The emoji used for the reaction (null if removed) |
| isRemoved | boolean | true if the reaction was removed, false if added |
| messageKey | object | The message key object that was reacted to |
| timestamp | Date | When the reaction event was processed |
| raw | object | Raw reaction data from Baileys |#### Sending Reactions
You can also send reactions to messages programmatically:
`javascript
// React to a message
await client.sendMessage(chatId, {
type: 'reaction',
emoji: 'ā¤ļø',
messageKey: messageToReactTo.key
})// Remove a reaction (send empty emoji)
await client.sendMessage(chatId, {
type: 'reaction',
emoji: '',
messageKey: messageToReactTo.key
})
`$3
`javascript
// Listen for LID/PN mapping updates
client.on('lid-mapping-update', (update) => {
console.log('New LID/PN mappings received:', update)
// Handle new mappings as needed
})
`$3
`javascript
// Global error handler
client.on('error', error => {
console.error('Client Error:', error)
// Handle specific error types
if (error.message.includes('Connection Closed')) {
console.log('Attempting to reconnect...')
client.connect()
}
})// Example with try-catch
try {
await client.sendMessage(to, message)
} catch (error) {
console.error('Error sending message:', error)
if (error.message.includes('Not connected')) {
console.log('Reconnecting...')
await client.connect()
}
}
`Baileys v7.x.x LID Store Implementation
$3
This library fully supports Baileys v7.x.x LID (Local Identifier) system for enhanced privacy and WhatsApp's transition to username-based identification.
| Feature | Description |
|---------|-------------|
| LID Support | Full support for Local Identifiers alongside Phone Numbers |
| Store Access | Automatic initialization via
client.sock.signalRepository.lidMapping |
| Helper Methods | getLIDForPN(), getPNForLID(), getLIDsForPNs() |
| Event Handling | lid-mapping-update event for real-time mapping updates |
| Message Handling | Automatic preference for PN over LID with fallback support |
| Compatibility | Backward compatible with v6.x code patterns |$3
LID (Local Identifier) is WhatsApp's privacy feature that replaces phone numbers in large groups. Key points:
- Unique per user (not per group)
- Ensures user anonymity in large groups
- Allows messaging users via either LID or PN (Phone Number)
- Part of WhatsApp's transition to username system (@username)
#### JID Format Changes
- PN (Phone Number):
1234567890@s.whatsapp.net (traditional format)
- LID: 123456@lid (new format)$3
The store is automatically initialized when you create a WhatsAppClient and is accessible via the internal socket:
`javascript
const client = new WhatsAppClient({ sessionName: ".Sessions" });
await client.connect();// Store is available internally as client.store
// Access via: client.sock.signalRepository.lidMapping
`$3
The WhatsAppClient provides convenient methods to work with LID/PN mappings:
#### Quick Reference
`javascript
// Get LID from Phone Number
const lid = await client.getLIDForPN('1234567890@s.whatsapp.net');// Get Phone Number from LID
const pn = await client.getPNForLID('123456@lid');
// Get multiple LIDs
const lids = await client.getLIDsForPNs(['phone1@s.whatsapp.net', 'phone2@s.whatsapp.net']);
`#### Detailed Examples
`javascript
// Get LID from Phone Number
const lid = await client.getLIDForPN('1234567890@s.whatsapp.net');
console.log('LID:', lid);// Get Phone Number from LID
const pn = await client.getPNForLID('123456@lid');
console.log('Phone Number:', pn);
// Get multiple LIDs from multiple PNs
const lids = await client.getLIDsForPNs([
'1234567890@s.whatsapp.net',
'0987654321@s.whatsapp.net'
]);
console.log('LIDs:', lids);
`$3
The library automatically handles both LID and PN formats in messages:
`javascript
client.on('message', async msg => {
// msg.from will prefer PN over LID when available
console.log('Message from:', msg.from);
// Access raw message key for both formats
const remoteJid = msg.raw.key.remoteJid; // Primary JID
const remoteJidAlt = msg.raw.key.remoteJidAlt; // Alternate JID
// For group messages
const participant = msg.raw.key.participant; // Could be LID or PN
const participantAlt = msg.raw.key.participantAlt; // Alternate format
// Convert LID to PN if needed
if (remoteJid.endsWith('@lid')) {
const phoneNumber = await client.getPNForLID(remoteJid);
console.log('Phone number:', phoneNumber);
}
});
`$3
#### 1. Prefer PN over LID for Compatibility
`javascript
const getPreferredJid = (messageKey) => {
if (messageKey.remoteJidAlt?.endsWith('@s.whatsapp.net')) {
return messageKey.remoteJidAlt; // Use PN
}
return messageKey.remoteJid; // Fallback to primary JID
};
`#### 2. Convert LID to PN When Needed
`javascript
const convertToPN = async (jid) => {
if (jid.endsWith('@lid')) {
const pn = await client.getPNForLID(jid);
return pn || jid; // Return PN if found, otherwise return LID
}
return jid;
};
`#### 3. Handle Both Formats Gracefully
`javascript
// Always handle undefined returns
const lid = await client.getLIDForPN(phoneNumber);
if (lid) {
console.log('LID found:', lid);
} else {
console.log('No LID mapping available, using PN');
}
`$3
#### Getting User's LID
`javascript
client.on('message', async msg => {
if (msg.body === '!myid') {
const lid = await client.getLIDForPN(msg.from);
if (lid) {
await msg.reply(Your LID: ${lid}\nYour PN: ${msg.from});
} else {
await msg.reply('No LID found. You may be using a PN-only session.');
}
}
});
`#### Resolving LID to Phone Number
`javascript
client.on('message', async msg => {
if (msg.body.startsWith('!lookup ')) {
const lid = msg.body.split(' ')[1];
const phoneNumber = await client.getPNForLID(lid);
if (phoneNumber) {
await msg.reply(Phone number: ${phoneNumber});
} else {
await msg.reply('No phone number found for that LID.');
}
}
});
`#### Handling Group Messages with LIDs
`javascript
client.on('message', async msg => {
if (msg.isGroup) {
const participant = msg.raw.key.participant;
const participantAlt = msg.raw.key.participantAlt;
// Use alternate (PN) if available, otherwise use primary
const senderJid = participantAlt || participant;
console.log('Group message from:', senderJid);
// Get LID if sender is using PN
if (senderJid.endsWith('@s.whatsapp.net')) {
const lid = await client.getLIDForPN(senderJid);
console.log('Sender LID:', lid);
}
}
});
`$3
`javascript
// Check if JID is a Phone Number
const isPnUser = (jid) => {
return jid?.endsWith('@s.whatsapp.net');
};// Check if JID is a LID
const isLidUser = (jid) => {
return jid?.endsWith('@lid');
};
// Get preferred JID format
const getPreferredFormat = async (jid, client) => {
if (isLidUser(jid)) {
const pn = await client.getPNForLID(jid);
return pn || jid;
}
return jid;
};
`$3
ā ļø Important: Your authentication state must support these keys:
-
lid-mapping - Stores LID/PN mappings
- device-list - Manages linked devices
- tctoken - Token for communicationsThe library handles this automatically with
useMultiFileAuthState.$3
If you're upgrading from Baileys v6.x:
1. Store access changed: Access via
sock.signalRepository.lidMapping instead of separate store parameter
2. New message key fields: Check for remoteJidAlt and participantAlt
3. Event listener: Add handler for lid-mapping-update event
4. Function naming: isJidUser() replaced with isPnUser()
5. Automatic handling: The WhatsAppClient already implements these changes$3
#### Store is undefined
Problem: Cannot access LID store methods
Solution: Ensure client is connected before accessing store:
`javascript
await client.connect();
// Wait for 'connected' event
client.on('connected', async () => {
// Now store methods are available
const lid = await client.getLIDForPN(phoneNumber);
});
`#### No LID found for PN
Problem:
getLIDForPN() returns undefinedPossible causes:
- User hasn't migrated to LID system yet
- No LID/PN mapping received from WhatsApp server
- Using old session that doesn't support LIDs
Solution: Always handle
undefined` returns gracefullyFor more detailed information about the LID system implementation, see:
- LID_STORE_GUIDE.md - Complete implementation guide
- Baileys Migration Guide - Official migration documentation
- example.js - Working examples with LID handling
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Developed by Innovators Soft. Based on the @itsukichan/baileys library.