
Research
/Security News
Critical Vulnerability in NestJS Devtools: Localhost RCE via Sandbox Escape
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
evolution-api-sdk
Advanced tools
Unofficial SDK for the Evolution Whatsapp API (v2).
This is a fork of @solufy/evolution-sdk with additional features.
npm install evolution-api-sdk
// or
yarn add evolution-api-sdk
// or
bun add evolution-api-sdk
import { EvolutionClient } from "evolution-api-sdk";
const client = new EvolutionClient({
serverUrl: "Your server url",
token: "Global api key or instance token",
instance: "Your instance", // optional
});
client.setInstance("my-instance-01");
await client.messages.sendText({
number: "5511999999999",
text: "Hello from the SDK!",
});
You can override the default instance for any method call:
// Send message using a different instance
await client.messages.sendText(
{
number: "5511999999999",
text: "Hello from another instance!",
},
{ instance: "different-instance-name" }
);
// Check numbers on a specific instance
await client.chats.check(["5511999999999"], { instance: "my-instance" });
// Works with all methods across all modules
await client.groups.create(
{
subject: "My Group",
participants: ["5511999999999"],
},
{ instance: "work-instance" }
);
await client.profile.updateName(
{
name: "New Name",
},
{ instance: "personal-instance" }
);
await client.messages.sendImage({
number: "5511999999999",
image: "https://i.imgur.com/REo1ODy.png",
caption: "A cute cat",
});
await client.groups.create({
subject: "My Awesome Group",
participants: ["5511999999999", "5522988888888"],
});
const result = await client.chats.check(["5511999999999"]);
console.log(result);
// [{ jid: '5511999999999@s.whatsapp.net', exists: true }]
💡 Pro Tip: All methods support an optional
{ instance: "instance-name" }
parameter to override the default instance.
await client.instance.create({
instanceName: "my-bot",
token: "optional-token",
});
await client.setInstance("InstanceName");
await client.instance.connect({ instanceName: "my-bot" });
const state = await client.instance.connectionState({ instanceName: "my-bot" });
// Logout
await client.instance.logout({ instanceName: "my-bot" });
// Restart
await client.instance.restart({ instanceName: "my-bot" });
// Delete
await client.instance.delete({ instanceName: "my-bot" });
// List all instances
const instances = await client.instance.fetchAll();
// Set presence
await client.instance.setPresence({
instanceName: "my-bot",
presence: "available",
});
const result = await client.chats.check(["5511999999999", "5522888888888"]);
// Override instance: client.chats.check(numbers, { instance: "my-instance" })
const chats = await client.chats.findAll();
client.setInstance("my-instance-01");
// Update presence
await client.chats.updatePresence({
number: "5511999999999",
presence: "composing",
delay: 1000,
});
// Mark as read
await client.chats.markAsRead({
remoteJid: "5511999999999@s.whatsapp.net",
fromMe: false,
id: "message-id",
});
// Archive chat
await client.chats.archive({
remoteJid: "5511999999999@s.whatsapp.net",
archive: true,
});
// Delete message
await client.chats.deleteMessage({
remoteJid: "5511999999999@s.whatsapp.net",
fromMe: true,
id: "message-id",
});
// Find messages
const messages = await client.chats.findMessages({
remoteJid: "5511999999999@s.whatsapp.net",
limit: 50,
});
// Update message
await client.chats.updateMessage({
remoteJid: "5511999999999@s.whatsapp.net",
fromMe: true,
id: "message-id",
text: "Updated message",
});
// Fetch profile picture
const profilePic = await client.chats.fetchProfilePicture({
number: "5511999999999",
});
// Find contacts
const contacts = await client.chats.findContacts({
where: { name: "John" },
});
await client.messages.sendText({
number: "5511999999999",
text: "Hello! 👋",
});
// Send image
await client.messages.sendImage({
number: "5511999999999",
image: "https://example.com/image.jpg",
caption: "Check this out!",
});
// Send video
await client.messages.sendVideo({
number: "5511999999999",
video: "https://example.com/video.mp4",
caption: "Amazing video!",
});
// Send document
await client.messages.sendDocument({
number: "5511999999999",
document: "https://example.com/document.pdf",
fileName: "report.pdf",
});
// Send audio
await client.messages.sendAudio({
number: "5511999999999",
audio: "https://example.com/audio.mp3",
});
// Send location
await client.messages.sendLocation({
number: "5511999999999",
latitude: -23.5505,
longitude: -46.6333,
name: "São Paulo",
});
// Send contact
await client.messages.sendContact({
number: "5511999999999",
contact: [
{
fullName: "John Doe",
phones: ["5511999999999"],
},
],
});
// Send reaction
await client.messages.sendReaction({
reactionMessage: {
key: { remoteJid: "5511999999999@s.whatsapp.net", id: "message-id" },
text: "👍",
},
});
// Send list
await client.messages.sendList({
number: "5511999999999",
title: "Choose an option",
description: "Select from the options below",
sections: [
{
title: "Options",
rows: [
{ title: "Option 1", description: "First option" },
{ title: "Option 2", description: "Second option" },
],
},
],
});
// Send template
await client.messages.sendTemplate({
number: "5511999999999",
template: {
name: "hello_world",
language: { code: "en_US" },
},
});
// Create group
await client.groups.create({
subject: "My Awesome Group",
participants: ["5511999999999", "5522888888888"],
});
// Get all groups
const groups = await client.groups.findAll(false); // without participants
const groupsWithMembers = await client.groups.findAll(true); // with participants
// Find group by invite code
const group = await client.groups.findByInviteCode("invite-code-here");
// Find group by JID
const group = await client.groups.findByJid("group-id@g.us");
// Update group subject
await client.groups.updateSubject({
groupJid: "group-id@g.us",
subject: "New Group Name",
});
// Update group description
await client.groups.updateDescription({
groupJid: "group-id@g.us",
description: "New group description",
});
// Update group picture
await client.groups.updatePicture({
groupJid: "group-id@g.us",
image: "https://example.com/group-pic.jpg",
});
// Add/remove members
await client.groups.updateMembers({
groupJid: "group-id@g.us",
action: "add",
participants: ["5511999999999"],
});
// Get group members
const members = await client.groups.findMembers({
groupJid: "group-id@g.us",
});
// Leave group
await client.groups.leave({
groupJid: "group-id@g.us",
});
// Get invite code
const inviteCode = await client.groups.fetchInviteCode({
groupJid: "group-id@g.us",
});
// Revoke invite code
await client.groups.revokeInviteCode({
groupJid: "group-id@g.us",
});
// Accept invite
await client.groups.acceptInviteCode({
inviteCode: "invite-code-here",
});
// Get profile
const profile = await client.profile.fetchProfile({
number: "5511999999999",
});
// Get business profile
const businessProfile = await client.profile.fetchBusinessProfile({
number: "5511999999999",
});
// Update name
await client.profile.updateName({
name: "My New Name",
});
// Update status
await client.profile.updateStatus({
status: "Hey there! I'm using WhatsApp",
});
// Update picture
await client.profile.updatePicture({
picture: "https://example.com/my-photo.jpg",
});
// Remove picture
await client.profile.removePicture();
// Get privacy settings
const privacy = await client.profile.fetchPrivacySettings();
// Update privacy settings
await client.profile.updatePrivacySettings({
privacySettings: {
readReceipts: "all",
profile: "contacts",
status: "contacts",
online: "all",
last: "contacts",
groupAdd: "contacts",
},
});
// Get settings
const settings = await client.settings.find();
// Update settings
await client.settings.set({
reject_call: true,
msg_call: "Sorry, I can't take calls right now",
groups_ignore: false,
});
// Get webhook settings
const webhook = await client.webhook.find();
// Set webhook
await client.webhook.set({
url: "https://your-webhook-url.com/webhook",
webhook_by_events: true,
events: ["MESSAGES_UPSERT", "CONNECTION_UPDATE"],
});
You can override the default instance for any method:
// Send message with different instance
await client.messages.sendText(
{
number: "5511999999999",
text: "Hello from work bot!",
},
{ instance: "work-instance" }
);
// Check numbers on personal instance
await client.chats.check(["5511999999999"], { instance: "personal-bot" });
// Create group on specific instance
await client.groups.create(
{
subject: "Team Meeting",
participants: ["5511999999999"],
},
{ instance: "team-bot" }
);
The SDK provides complete TypeScript support for handling webhooks from the Evolution API.
import express from "express";
import {
WebhookData,
WebhookEvent,
WebhookEventSetup,
MessagePayload,
ContactPayload,
ConnectionUpdatePayload,
} from "evolution-api-sdk";
const app = express();
app.use(express.json());
// Webhook endpoint
app.post("/webhook", async (req, res) => {
try {
const webhookData: WebhookData = req.body;
await processWebhook(webhookData);
res.status(200).send("OK");
} catch (error) {
console.error("Webhook processing error:", error);
res.status(500).send("Error");
}
});
app.listen(3000, () => {
console.log("Webhook server running on port 3000");
});
async function processWebhook(webhookData: WebhookData): Promise<void> {
const { event, instance, data } = webhookData;
console.log(`[WEBHOOK] Event: ${event} | Instance: ${instance}`);
switch (event) {
case WebhookEvent.MESSAGES_UPSERT:
await handleNewMessage(data as MessagePayload, instance);
break;
case WebhookEvent.MESSAGES_UPDATE:
await handleMessageUpdate(data as MessagePayload, instance);
break;
case WebhookEvent.CONNECTION_UPDATE:
await handleConnectionUpdate(data as ConnectionUpdatePayload);
break;
case WebhookEvent.CONTACTS_UPSERT:
case WebhookEvent.CONTACTS_UPDATE:
await handleContact(data as ContactPayload, instance);
break;
case WebhookEvent.QRCODE_UPDATED:
console.log(`[WEBHOOK] QR Code updated for instance: ${instance}`);
break;
default:
console.log(`[WEBHOOK] Unhandled event: ${event}`);
}
}
async function handleNewMessage(
messageData: MessagePayload,
instance: string
): Promise<void> {
const { key, message, pushName } = messageData;
// Skip messages from groups (optional)
if (key.remoteJid?.includes("@g.us")) {
console.log("Skipping group message");
return;
}
// Skip messages sent by bot itself
if (key.fromMe) {
console.log("Skipping outgoing message");
return;
}
const from = key.remoteJid;
const messageId = key.id;
const contactName = pushName || "Unknown";
console.log(`Message from ${contactName} (${from}): ${messageId}`);
// Process different message types
if (message?.conversation) {
// Text message
const text = message.conversation;
console.log(`Text: ${text}`);
// Auto-reply example
if (text.toLowerCase() === "hello") {
await client.messages.sendText(
{
number: from.replace("@s.whatsapp.net", ""),
text: "Hello! How can I help you?",
},
{ instance }
);
}
} else if (message?.imageMessage) {
// Image message
console.log(`Received image from ${contactName}`);
const imageUrl = message.imageMessage.url;
// Process image...
} else if (message?.audioMessage) {
// Audio message
console.log(`Received audio from ${contactName}`);
// Process audio...
}
}
async function handleMessageUpdate(
messageData: MessagePayload,
instance: string
): Promise<void> {
const { key, status } = messageData;
console.log(`Message ${key.id} status updated to: ${status}`);
// Handle read receipts, delivery confirmations, etc.
switch (status) {
case "delivered":
console.log("Message delivered");
break;
case "read":
console.log("Message read by recipient");
break;
}
}
async function handleConnectionUpdate(
connectionData: ConnectionUpdatePayload
): Promise<void> {
const { instance, state, statusReason } = connectionData;
console.log(`Instance ${instance} connection state: ${state}`);
switch (state) {
case "open":
console.log(`✅ Instance ${instance} connected successfully`);
break;
case "close":
console.log(`❌ Instance ${instance} disconnected (${statusReason})`);
break;
case "connecting":
console.log(`🔄 Instance ${instance} connecting...`);
break;
}
}
async function handleContact(
contactData: ContactPayload,
instance: string
): Promise<void> {
const { remoteJid, pushName, profilePicUrl } = contactData;
console.log(`Contact update: ${pushName} (${remoteJid})`);
// Store or update contact information
// You might want to save this to your database
}
class WebhookProcessor {
private messageQueue: MessagePayload[] = [];
private processing = false;
async processWebhook(webhookData: WebhookData): Promise<void> {
const { event, data, instance } = webhookData;
// Add message to queue for batch processing
if (event === WebhookEvent.MESSAGES_UPSERT) {
this.messageQueue.push(data as MessagePayload);
this.processQueue();
}
}
private async processQueue(): Promise<void> {
if (this.processing || this.messageQueue.length === 0) return;
this.processing = true;
try {
// Process messages in batches
const batch = this.messageQueue.splice(0, 10);
for (const message of batch) {
await this.processMessage(message);
// Add delay to avoid rate limiting
await new Promise((resolve) => setTimeout(resolve, 100));
}
} finally {
this.processing = false;
// Continue processing if more messages arrived
if (this.messageQueue.length > 0) {
setTimeout(() => this.processQueue(), 1000);
}
}
}
private async processMessage(message: MessagePayload): Promise<void> {
// Your message processing logic here
console.log(`Processing message: ${message.key.id}`);
}
}
The SDK supports all Evolution API webhook events:
WebhookEvent.APPLICATION_STARTUP
- API startupWebhookEvent.QRCODE_UPDATED
- QR code updatesWebhookEvent.CONNECTION_UPDATE
- Connection status changesWebhookEvent.MESSAGES_SET
- Initial message loadWebhookEvent.MESSAGES_UPSERT
- New messagesWebhookEvent.MESSAGES_UPDATE
- Message status updatesWebhookEvent.MESSAGES_DELETE
- Message deletionsWebhookEvent.SEND_MESSAGE
- Message sending eventsWebhookEvent.CONTACTS_SET
- Initial contacts loadWebhookEvent.CONTACTS_UPSERT
- New contactsWebhookEvent.CONTACTS_UPDATE
- Contact updatesWebhookEvent.PRESENCE_UPDATE
- User presence changesWebhookEvent.CHATS_SET
- Initial chats loadWebhookEvent.CHATS_UPDATE
- Chat updatesWebhookEvent.CHATS_UPSERT
- New chatsWebhookEvent.CHATS_DELETE
- Chat deletionsWebhookEvent.GROUPS_UPSERT
- New groupsWebhookEvent.GROUPS_UPDATE
- Group updatesWebhookEvent.GROUP_PARTICIPANTS_UPDATE
- Group member changesWebhookEvent.NEW_TOKEN
- JWT token updatesTo setup the WebHook, the constants are these ones:
WebhookEventSetup.APPLICATION_STARTUP
- API startupWebhookEventSetup.QRCODE_UPDATED
- QR code updatesWebhookEventSetup.CONNECTION_UPDATE
- Connection status changesWebhookEventSetup.MESSAGES_SET
- Initial message loadWebhookEventSetup.MESSAGES_UPSERT
- New messagesWebhookEventSetup.MESSAGES_UPDATE
- Message status updatesWebhookEventSetup.MESSAGES_DELETE
- Message deletionsWebhookEventSetup.SEND_MESSAGE
- Message sending eventsWebhookEventSetup.CONTACTS_SET
- Initial contacts loadWebhookEventSetup.CONTACTS_UPSERT
- New contactsWebhookEventSetup.CONTACTS_UPDATE
- Contact updatesWebhookEventSetup.PRESENCE_UPDATE
- User presence changesWebhookEventSetup.CHATS_SET
- Initial chats loadWebhookEventSetup.CHATS_UPDATE
- Chat updatesWebhookEventSetup.CHATS_UPSERT
- New chatsWebhookEventSetup.CHATS_DELETE
- Chat deletionsWebhookEventSetup.GROUPS_UPSERT
- New groupsWebhookEventSetup.GROUPS_UPDATE
- Group updatesWebhookEventSetup.GROUP_PARTICIPANTS_UPDATE
- Group member changesWebhookEventSetup.NEW_TOKEN
- JWT token updatesDon't forget to configure your webhook URL in the Evolution API:
// Set your webhook endpoint
await client.webhook.set({
url: "https://your-domain.com/webhook",
webhook_by_events: true,
events: [
WebhookEventSetup.MESSAGES_UPSERT,
WebhookEventSetup.MESSAGES_UPDATE,
WebhookEventSetup.CONNECTION_UPDATE,
WebhookEventSetup.CONTACTS_UPSERT,
],
});
Check the official API documentation for more information about their service.
Feel free to contribute with suggestions or bug reports at our GitHub repository.
FAQs
Unofficial SDK for the Evolution Whatsapp API v2
The npm package evolution-api-sdk receives a total of 450 weekly downloads. As such, evolution-api-sdk popularity was classified as not popular.
We found that evolution-api-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
Product
Customize license detection with Socket’s new license overlays: gain control, reduce noise, and handle edge cases with precision.
Product
Socket now supports Rust and Cargo, offering package search for all users and experimental SBOM generation for enterprise projects.