innovators-bot2
v2.0.1
Published
WhatsApp API
Maintainers
Readme
INNOVATORS SOFT WhatsApp Bot 2
A 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.
Features
- 🚀 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
Installation
npm install innovators-bot2Quick Start With Qr Code
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
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()Usage Examples
1. Basic Messaging
// Send a text message
await client.sendMessage('[email protected]', 'Hello world!')
// Send a reply
await client.reply('[email protected]', 'This is a reply', {
quoted: originalMessage
})
// Send with mentions
await client.sendMessage('[email protected]', {
type: 'text',
text: 'Hey @user!',
mentions: ['[email protected]']
})2. Media Handling
// Send an image
await client.sendMedia('[email protected]', './image.jpg', {
caption: 'Check out this image!'
})
// Send a document
await client.sendDocument('[email protected]', './document.pdf',
'Check out this document!'
)3. Sticker Management
Create stickers easily from any image buffer with automatic conversion and metadata support.
const fs = require('fs');
// Send a sticker from an image or video buffer
const buffer = fs.readFileSync('./image.jpg');
await client.sendSticker('[email protected]', buffer, {
packName: 'Innovators',
author: 'Innovators Bot',
type: 'full', // 'full' or 'crop'
quality: 50
});4. Anti-Delete System
The library includes a built-in Anti-Delete system that tracks deleted messages in real-time.
// Listen for deleted messages
client.on('message-deleted', async (data) => {
console.log(`User ${data.jid} deleted a message!`);
// 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
});
});5. Group Management
// Get all groups
const groups = await client.getAllGroups()
// Get group metadata (participants, name, description...)
const metadata = await client.getGroupMetadata(groupId)
console.log(metadata.id, metadata.subject, metadata.desc)
// Create a new group
const newGroup = await client.createGroup('Group Name', ['[email protected]'])
console.log('Created group:', newGroup.id)
// Change group subject (name)
await client.changeGroupSubject(groupId, 'New Group Name')
// Change group description
await client.changeGroupDescription(groupId, 'New description for the group')
// Change group settings
// Options: 'announcement' (only admins send), 'not_announcement' (everyone sends),
// 'locked' (only admins edit info), 'unlocked' (everyone edits info)
await client.changeGroupSettings(groupId, 'announcement')
// Get group invite code
const code = await client.getGroupInviteCode(groupId)
console.log('Invite link: https://chat.whatsapp.com/' + code)
// Revoke invite code (generates a new one)
const newCode = await client.revokeGroupInviteCode(groupId)
console.log('New invite link: https://chat.whatsapp.com/' + newCode)
// Join group by invite code
const joinedGroupId = await client.joinGroupByInviteCode('AbCdEfGhIjK')
// Also accepts full URL - it strips the prefix automatically
await client.joinGroupByInviteCode('https://chat.whatsapp.com/AbCdEfGhIjK')
// Get group info by invite code (without joining)
const groupInfo = await client.getGroupInfoByInviteCode('AbCdEfGhIjK')
console.log('Group name:', groupInfo.subject)
// Leave a group
await client.leaveGroup(groupId)
// 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, ['[email protected]'], '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, '[email protected]', 'Join my group!')
// Remove participant
await client.changeGroupParticipants(groupId, ['[email protected]'], 'remove')
// Promote to admin
await client.changeGroupParticipants(groupId, ['[email protected]'], 'promote')
// Demote admin
await client.changeGroupParticipants(groupId, ['[email protected]'], 'demote')
// Get pending join requests
const requests = await client.getGroupJoinRequests(groupId)
console.log('Pending requests:', requests)
// Approve/Reject join requests
await client.handleGroupJoinRequest(groupId, ['[email protected]'], 'approve')
await client.handleGroupJoinRequest(groupId, ['[email protected]'], 'reject')
// Toggle ephemeral (disappearing) messages
// Options: 0 (off), 86400 (24h), 604800 (7d), 7776000 (90d)
await client.toggleGroupEphemeral(groupId, 86400)
// Change who can add members
// Options: 'all_member_add' or 'admin_add'
await client.changeGroupAddMode(groupId, 'admin_add')6. Privacy Management
// Block a user
await client.blockUser('[email protected]')
// Unblock a user
await client.unblockUser('[email protected]')
// Get all privacy settings
const settings = await client.getPrivacySettings()
console.log('Privacy settings:', settings)
// Get blocked contacts list
const blocklist = await client.getBlockList()
console.log('Blocked users:', blocklist)
// Update last seen privacy
// Options: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateLastSeenPrivacy('contacts')
// Update online status privacy
// Options: 'all' | 'match_last_seen'
await client.updateOnlinePrivacy('match_last_seen')
// Update profile picture privacy
// Options: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateProfilePicturePrivacy('contacts')
// Update status privacy
// Options: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateStatusPrivacy('contacts')
// Update read receipts privacy
// Options: 'all' | 'none'
await client.updateReadReceiptsPrivacy('all')
// Update who can add you to groups
// Options: 'all' | 'contacts' | 'contact_blacklist'
await client.updateGroupsAddPrivacy('contacts')
// Update default disappearing mode for new chats
// Options: 0 (off), 86400 (24h), 604800 (7d), 7776000 (90d)
await client.updateDefaultDisappearingMode(604800)7. Interactive Messages
Buttons
// Send interactive buttons
await client.sendButtons('[email protected]', {
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
// Send interactive list
await client.SendList('[email protected]', {
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' }
]
}
]
});8. Message History
// Get chat history
const messages = await client.loadMessages(chatId, 50)
// Get specific message
const message = await client.loadMessage(chatId, messageId)More Examples and Information
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.
Bot Commands
The library includes example bot commands that you can use:
Basic Commands
!ping- Check if bot is alive!echo <text>- Echo back your text!help- Show all available commands
Messaging
!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!recording- Show recording indicator!paused- Clear typing or recording indicator
Media & Content
!media- Send an example image!doc- Send an example document!location- Send a location!contact- Send a contact card!sticker- Create a sticker from an image!ad- Send an ad reply message
Group Management
!groups- List all your groups!add <number>- Add participant to group!remove <number>- Remove participant from group!promote <number>- Promote participant to admin!demote <number>- Demote admin to participant!invite <number>- Send group invite link to user!creategroup <name>- Create a new group!groupsubject <name>- Change group name!groupdesc <text>- Change group description!groupsetting <setting>- Change group settings (announcement/not_announcement/locked/unlocked)!invitecode- Get group invite code/link!revokeinvite- Revoke current invite code and generate new one!leavegroup- Leave the current group!joingroup <code>- Join a group by invite code!groupinfo <code>- Get group info by invite code without joining!joinrequests- List pending join requests!approvejoin <number>- Approve a join request!rejectjoin <number>- Reject a join request!ephemeral <seconds>- Toggle disappearing messages (0/86400/604800/7776000)!addmode <mode>- Change who can add members (all_member_add/admin_add)
🔒 Privacy
!block <number>- Block a user!unblock <number>- Unblock a user!privacy- View all privacy settings!blocklist- List all blocked contacts!lastseenprivacy <value>- Update last seen privacy (all/contacts/contact_blacklist/none)!onlineprivacy <value>- Update online privacy (all/match_last_seen)!pfpprivacy <value>- Update profile picture privacy (all/contacts/contact_blacklist/none)!statusprivacy <value>- Update status privacy (all/contacts/contact_blacklist/none)!readreceiptprivacy <value>- Update read receipts privacy (all/none)!groupaddprivacy <value>- Update who can add you to groups (all/contacts/contact_blacklist)!disappearing <seconds>- Update default disappearing mode (0/86400/604800/7776000)
Interactive Messages
!buttons- Show interactive buttons!list- Display a scrollable list!logout- Logout from current session
🛡️ Protection
Anti-Delete- Automatically tracks and emits events for deleted messages
🔐 JID & LID/PN Management (v7.x.x)
!lid- Get your LID (Local Identifier)!pn <lid>- Get phone number from a LID!parse <jid>- Parse detailed JID information!normalize <number>- Normalize a number to JID format
Connection Events
// 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)
})Message Events
// 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
}
})Message Reaction Events
Listen for when users add or remove reactions (emojis) from messages:
// 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:
// 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
})LID Mapping Events
// 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
})Error Handling
// 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
Overview
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 |
What are LIDs?
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):
[email protected](traditional format) - LID:
123456@lid(new format)
Accessing the Store
The store is automatically initialized when you create a WhatsAppClient and is accessible via the internal socket:
const client = new WhatsAppClient({ sessionName: ".Sessions" });
await client.connect();
// Store is available internally as client.store
// Access via: client.sock.signalRepository.lidMappingAvailable Methods
The WhatsAppClient provides convenient methods to work with LID/PN mappings:
Quick Reference
// Get LID from Phone Number
const lid = await client.getLIDForPN('[email protected]');
// Get Phone Number from LID
const pn = await client.getPNForLID('123456@lid');
// Get multiple LIDs
const lids = await client.getLIDsForPNs(['[email protected]', '[email protected]']);Detailed Examples
// Get LID from Phone Number
const lid = await client.getLIDForPN('[email protected]');
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([
'[email protected]',
'[email protected]'
]);
console.log('LIDs:', lids);Message Handling with LID Support
The library automatically handles both LID and PN formats in messages:
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);
}
});Best Practices
1. Prefer PN over LID for Compatibility
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
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
// 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');
}Common Use Cases
Getting User's LID
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
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
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);
}
}
});Helper Functions
// 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;
};Authentication State Requirements
⚠️ Important: Your authentication state must support these keys:
lid-mapping- Stores LID/PN mappingsdevice-list- Manages linked devicestctoken- Token for communications
The library handles this automatically with useMultiFileAuthState.
Migration from v6.x to v7.x
If you're upgrading from Baileys v6.x:
- Store access changed: Access via
sock.signalRepository.lidMappinginstead of separate store parameter - New message key fields: Check for
remoteJidAltandparticipantAlt - Event listener: Add handler for
lid-mapping-updateevent - Function naming:
isJidUser()replaced withisPnUser() - Automatic handling: The WhatsAppClient already implements these changes
Troubleshooting
Store is undefined
Problem: Cannot access LID store methods
Solution: Ensure client is connected before accessing store:
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 undefined
Possible 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 gracefully
Additional Resources
For 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
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Credits
Developed by Innovators Soft. Based on the @itsukichan/baileys library.
