@sheikhtamim/wca
v1.1.1
Published
FCA-style WhatsApp Client API built on Baileys — send messages, media, manage groups, and listen to all WhatsApp events with a familiar callback interface.
Maintainers
Readme
WCA is an FCA-style WhatsApp bot framework built on top of Baileys.
If you know how to write a Facebook Messenger bot usingstfca, you already know WCA.
📦 NPM • 🤖 Example Bot • 🐛 Issues • 💬 Support Group • 📸 Instagram
✨ Features
| Category | Feature | |---|---| | 🔌 Connection | QR Code login · Pairing Code (no phone scan) · Auto-reconnect | | 💬 Messaging | Send text · Reply/quote · Mentions · Emoji reactions · Delete for everyone · Edit message · Send poll | | 📎 Media | Image · Video · Audio · PTT/Voice · Document · Sticker · GIF · Location | | 👥 Groups | Create · Leave · Add/Kick · Promote/Demote · Rename · Description · Invite link · Settings · Pin message · Get all groups | | 👤 Profile | Get/Set profile picture · Status text · Display name · Block/Unblock · Get DM info | | 📡 Events | Messages · Reactions · Delete events · Group changes · Typing presence · Calls | | 💬 Chats | Get all chats · Get all contacts · Archive/Unarchive · Mute/Unmute | | 🔄 Updates | Auto-update on startup — always keeps itself current |
📋 Requirements
- Node.js ≥ 18.x (LTS recommended — download)
- npm ≥ 8.x
- A WhatsApp account
# Check your versions
node -v
npm -v📦 Installation
npm install @sheikhtamim/wca🚀 Quick Start
QR Code login
const wca = require('@sheikhtamim/wca');
wca({ authFolder: './wca_auth' }, (err, api) => {
if (err) return console.error(err);
api.listen((err, msg) => {
if (err || !msg || msg.type !== 'message') return;
if (msg.body === '!ping') {
api.sendMessage('🏓 Pong!', msg.threadID);
}
});
});Pairing Code login (no QR scan needed)
const wca = require('@sheikhtamim/wca');
wca({
authFolder: './wca_auth',
phoneNumber: '8801xxxxxxxxx', // international format, no +
usePairingCode: true,
}, (err, api) => {
if (err) return console.error(err);
console.log('Connected as', api.getCurrentUserID());
api.listen((err, msg) => {
if (!msg || msg.type !== 'message') return;
if (msg.body === '!ping') {
api.sendMessage('🏓 Pong!', msg.threadID);
}
});
});When the pairing code prints in your console:
- Open WhatsApp → ⋮ Menu → Linked Devices
- Tap Link a device → Link with phone number instead
- Enter the code shown in your terminal
⚙️ Options
wca({
authFolder: './wca_auth', // auth state folder (default: './wca_auth')
phoneNumber: '628xxx', // for pairing code
usePairingCode: true, // force pairing code flow
skipUpdateCheck: false, // set true to skip auto-update on start
globalOptions: {
selfListen: false, // process own sent messages
selfListenEvent: false, // emit own messages to listen()
listenEvents: true, // emit group / call / presence events
updatePresence: false, // emit all presence updates
listenTyping: false, // emit only typing (composing/paused) events
autoMarkDelivery: false, // auto-read every received message
autoReconnect: true, // reconnect on unexpected drop
emitReady: false, // emit { type:'ready' } on connection open
enableTypingIndicator: false, // show typing before every sendMessage
typingDuration: 3000, // typing indicator duration ms
logLevel: 'error', // 'silent' | 'error' | 'warn' | 'info' | 'debug'
online: true, // appear online when connected
},
}, callback);🔄 Auto-Update (built-in)
WCA automatically checks for updates every time it starts and installs the latest version before connecting. No manual setup needed — just run your bot normally.
// WCA auto-updates itself. No extra code required.
wca({ authFolder: './wca_auth' }, (err, api) => { ... });To disable auto-update (not recommended):
wca({ skipUpdateCheck: true, authFolder: './wca_auth' }, (err, api) => { ... });You can also call it manually:
const { checkForWCAUpdate } = require('@sheikhtamim/wca/checkUpdate');
await checkForWCAUpdate();
// Options:
await checkForWCAUpdate({
autoUpdate: true, // install the update (default: true)
silent: false, // suppress console log (default: false)
exitOnUpdate: true, // exit(2) so pm2/nodemon restarts (default: true)
});📨 Message Event Format
{
type: 'message',
body: 'Hello!',
threadID: '[email protected]', // DM OR [email protected] (group)
senderID: '[email protected]', // always a phone JID (LIDs resolved)
author: '[email protected]', // alias for senderID
messageID: 'XXXXXXXXXXXXXXXXXX',
isGroup: false,
isSingleUser: true,
fromMe: false,
timestamp: 1716900000,
attachments: [ { type:'image', mimetype:'image/jpeg', caption:'...', ... } ],
mentions: [ '[email protected]' ],
replyToMessage: {
messageID: 'YYYYY',
senderID: '[email protected]',
body: 'quoted text',
attachments: [],
},
location: null, // { latitude, longitude, name, address } if location msg
poll: null, // { name, options, selectableCount } if poll msg
quoteOptions: { quoted: <rawWAMessage> }, // pass directly to sendMessage for reply
args: ['!ping'], // body.split(' ')
raw: <WAMessage>, // raw Baileys object
}Other event types
// Emoji reaction
{ type: 'message_reaction', emoji: '👍', reactionKey: { id, remoteJid, fromMe }, senderID, threadID, ... }
// Someone deleted a message
{ type: 'message_unsend', logMessageType: 'log:unsend', deletedMessageID, senderID, threadID, ... }
// Group participant change
{ type: 'event', logMessageType: 'log:subscribe'|'log:unsubscribe'|'log:thread-admins',
participants: ['[email protected]'], author, threadID, logMessageData: { action, ... } }
// Group metadata change
{ type: 'group_update', logMessageType: 'log:thread-name'|'log:thread-image'|'log:thread-description'|...,
threadID, author, logMessageData: { value } }
// Typing / presence
{ type: 'presence', userID, threadID, presence: 'composing'|'paused'|'available'|'unavailable', isTyping }
// Incoming call
{ type: 'call', from, isVideo, isGroup, status }📚 API Reference
Messaging
api.sendMessage(msg, threadID, [cb]) // text, attachment, reply, mention
api.sendImage(url, threadID, caption, opts)
api.sendVideo(url, threadID, caption, opts)
api.sendAudio(url, threadID, opts)
api.sendPTT(url, threadID, opts) // voice note
api.sendDocument(url, threadID, caption, opts)
api.sendSticker(url, threadID, opts)
api.sendGif(url, threadID, caption, opts)
api.sendLocation(threadID, lat, lon, opts)
api.sendTypingIndicator(bool, threadID)
api.markAsRead(threadID, senderID, [ids])
api.reactToMessage(threadID, msgID, emoji)
api.deleteMessage(threadID, msgID, forAll)
api.editMessage(threadID, msgID, newText) // edit a sent message
api.sendPoll(threadID, question, options, [opts]) // send a poll
api.pinMessage(threadID, msgID) // pin a message
api.unpinMessage(threadID, msgID) // unpin a message
api.downloadMedia(rawMsg) // → BufferQuoted reply
// Using quoteOptions from the incoming event (best):
api.sendMessage('Got it!', msg.threadID, null, { replyToMessage: msg.quoteOptions.quoted });
// Or pass the raw message directly:
api.sendMessage({ body: 'Reply!', replyToMessage: msg.raw }, msg.threadID);Groups
api.getGroupInfo(threadID) // full group info (for DB saving)
api.getAllGroups() // all groups the bot is in
api.getGroupAdmins(threadID)
api.getGroupInviteLink(threadID)
api.groupRevokeInvite(threadID)
api.groupAcceptInvite(code)
api.addUserToGroup(threadID, [userIDs])
api.kickUser(threadID, [userIDs])
api.createGroup(name, [participantIDs])
api.leaveGroup(threadID)
api.promoteAdmin(threadID, [userIDs])
api.demoteAdmin(threadID, [userIDs])
api.changeGroupSubject(threadID, name)
api.changeGroupDescription(threadID, desc)
api.groupSettingUpdate(threadID, setting) // 'announcement'|'not_announcement'|'locked'|'unlocked'Profile & user
api.getProfilePicture(userID, type)
api.getUserInfo([userIDs])
api.getDMInfo(userID) // full DM user info (for DB saving)
api.getContacts() // all contacts
api.getChats() // all chats / conversations
api.fetchStatus(userID)
api.updateProfilePicture(media)
api.updateProfileStatus(text)
api.updateProfileName(name)
api.blockContact(userID)
api.unblockContact(userID)
api.sendPresenceUpdate(type, threadID) // 'available'|'unavailable'|'composing'|'paused'
api.getCurrentUserID() // own JID
api.sock // raw Baileys socketChats
api.archiveChat(threadID, [archive=true]) // archive a chat
api.unarchiveChat(threadID) // unarchive a chat
api.muteChat(threadID, [durationMs]) // mute a chat (default 8 hours)
api.unmuteChat(threadID) // unmute a chat🗄️ Group / DM Info for Database
Get full group info (GC)
const info = await api.getGroupInfo('[email protected]');
// Returns:
// {
// threadID, name, description, owner, creation,
// size, adminIDs, participantIDs,
// participants: [{ userID, isAdmin, isSuperAdmin }],
// announcement, restrict, ephemeralDuration, raw
// }Get all groups the bot is in
const groups = await api.getAllGroups();
groups.forEach(g => console.log(g.name, g.size));Get full DM user info
const info = await api.getDMInfo('[email protected]');
// Returns:
// {
// userID, phone, name, status, statusTimestamp,
// profilePicture, isBusiness, businessProfile, isMe, raw
// }🤖 Full Bot Example
const wca = require('@sheikhtamim/wca');
// WCA auto-updates itself before connecting — no extra code needed.
wca({
authFolder: './wca_auth',
phoneNumber: '8801xxxxxxxxx',
usePairingCode: true,
globalOptions: {
listenEvents: true,
selfListen: false,
autoReconnect: true,
},
}, (err, api) => {
if (err) return console.error('WCA error:', err);
console.log('Bot ready:', api.getCurrentUserID());
api.listen(async (err, msg) => {
if (err) return;
if (!msg || msg.type !== 'message' || msg.fromMe) return;
const { body, threadID } = msg;
if (!body.startsWith('!')) return;
const [cmd, ...args] = body.slice(1).split(' ');
switch (cmd.toLowerCase()) {
case 'ping':
await api.sendMessage('🏓 Pong!', threadID);
break;
case 'poll':
await api.sendPoll(threadID, 'Favourite colour?', ['Red', 'Blue', 'Green']);
break;
case 'gcinfo':
if (msg.isGroup) {
const info = await api.getGroupInfo(threadID);
await api.sendMessage(
`*${info.name}*\nMembers: ${info.size}\nAdmins: ${info.adminIDs.length}`,
threadID
);
}
break;
case 'dminfo':
if (!msg.isGroup) {
const info = await api.getDMInfo(msg.senderID);
await api.sendMessage(
`Name: ${info.name || 'Unknown'}\nStatus: ${info.status || 'None'}`,
threadID
);
}
break;
case 'react':
await api.reactToMessage(threadID, msg.messageID, '👍');
break;
case 'reply':
await api.sendMessage(
{ body: 'This is a reply!', replyToMessage: msg.raw },
threadID
);
break;
case 'image':
await api.sendImage('https://picsum.photos/800/600', threadID, 'Test image');
break;
}
});
});📂 Project Structure
wca/
├── index.js ← Main entry wca(options, callback)
├── utils.js ← JID helpers, LID resolver, event formatter
├── checkUpdate.js ← Auto-update checker (runs on every startup)
└── src/ ← One file per feature
├── listenMqtt.js
├── sendMessage.js
├── sendMedia.js
├── sendPoll.js
├── editMessage.js
├── pinMessage.js
├── sendTypingIndicator.js
├── sendReadReceipt.js
├── sendLocation.js
├── sendPresenceUpdate.js
├── reactToMessage.js
├── deleteMessage.js
├── downloadMedia.js
├── getGroupInfo.js
├── getAllGroups.js
├── getGroupAdmins.js
├── getGroupInviteLink.js
├── groupRevokeInvite.js
├── groupAcceptInvite.js
├── groupSettingUpdate.js
├── addUserToGroup.js
├── kickUser.js
├── createGroup.js
├── leaveGroup.js
├── setGroupAdmin.js
├── changeGroupSubject.js
├── changeGroupDescription.js
├── getProfilePicture.js
├── getUserInfo.js
├── getDMInfo.js
├── getContacts.js
├── getChats.js
├── archiveChat.js
├── muteChat.js
├── fetchStatus.js
├── updateProfilePicture.js
├── updateProfileStatus.js
├── updateProfileName.js
├── blockContact.js
├── sendButtons.js
└── getAppState.js🧠 LID Resolution (Delta System)
WhatsApp internally uses LID (Linked Identity) JIDs — e.g. 186393124970625@lid — which are opaque internal IDs that differ from phone numbers. WCA automatically resolves these to real @s.whatsapp.net JIDs using Baileys' contact store.
msg.senderID→ always a phone JID ([email protected])msg.threadID→ group@g.usor phone JID for DMs- Device suffixes (
628xxx:[email protected]) are stripped automatically
🔗 Links
| | |
|---|---|
| 📦 NPM package | @sheikhtamim/wca |
| 🧩 WCA source | github.com/sheikhtamimlover/wca |
| 🤖 Example bot | github.com/sheikhtamimlover/ST_WhatsappBot |
| 💬 Support Group | Join WCA Support GC |
| 📸 Instagram | instagram.com/sheikh.tamim_lover |
| 📞 Contact | wa.me/8801600203673 |
Made with ❤️ by Sheikh Tamim
