.TH MANYBOT-PLUGIN 1 "April 2026" "ManyBot 2.4.3" "User Commands" .SH NAME manybot-plugin \- ManyBot plugin development guide .SH SYNOPSIS .B manyplug.json .I manifest file .br .I src/plugins/ .B plugin directory .SH DESCRIPTION ManyBot plugins extend the bot's functionality without modifying the core kernel. The kernel connects to WhatsApp and distributes messages to plugins, which decide how to respond. .PP Each plugin lives in its own folder under .I src/plugins/ with a .B manyplug.json manifest file and an .B index.js entry point. .SH PLUGIN STRUCTURE .nf src/plugins/ \(do__ my-plugin/ \(bu__ manyplug.json # Plugin manifest \(bu__ index.js # Main entry point \(bu__ locale/ # Translations (optional) \(bu__ en.json \(bu__ pt.json \(bu__ es.json .fi .SH MANIFEST (manyplug.json) Every plugin must include a manifest describing its metadata: .PP .nf { "name": "my-plugin", "version": "1.0.0", "category": "utility", "service": false, "dependencies": { "axios": "^1.6.0" } } .fi .TP .B name Plugin identifier. Must match the folder name. .TP .B version Semantic version (e.g., "1.0.0"). .TP .B category Plugin type: \fButility\fR, \fBmedia\fR, \fBgame\fR, \fBhumor\fR, or \fBinfo\fR. .TP .B service \fBtrue\fR for background plugins (schedulers, listeners). \fBfalse\fR for command/event-triggered plugins. .TP .B dependencies Extra npm packages required. Install with \fBnpm install\fR from project root. .SH PLUGIN ENTRY POINT The .I index.js file must export a default async function: .PP .nf .B "export default async function ({ msg, api }) {" // Plugin logic here .B "}" .fi .SS Parameters .TP .B msg Message object containing: .RS .IP \(bu 2 \fBbody\fR - Full message text .IP \(bu 2 \fBargs\fR - Array of message tokens .IP \(bu 2 \fBtype\fR - Message type: chat, image, video, audio, sticker, ptt, document, location .IP \(bu 2 \fBsender\fR - Sender ID (NUMBER@c.us or NUMBER@g.us) .IP \(bu 2 \fBsenderName\fR - Display name .IP \(bu 2 \fBfromMe\fR - True if bot sent the message .IP \(bu 2 \fBhasMedia\fR - True if contains media .IP \(bu 2 \fBhasReply\fR - True if it's a reply .IP \(bu 2 \fBisGif\fR - True if media is GIF .IP \(bu 2 \fBtimestamp\fR - Unix timestamp .IP \(bu 2 \fBis(cmd)\fR - Check if message starts with command .IP \(bu 2 \fBreply(text)\fR - Reply with quote .IP \(bu 2 \fBdownloadMedia()\fR - Download media (returns {mimetype, data}) .IP \(bu 2 \fBgetReply()\fR - Get quoted message object .RE .TP .B api API object containing: .RS .IP \(bu 2 \fBsend(text)\fR - Send text message .IP \(bu 2 \fBsendVideo(path)\fR - Send video file .IP \(bu 2 \fBsendAudio(path)\fR - Send audio as voice message .IP \(bu 2 \fBsendImage(path, caption?)\fR - Send image with optional caption .IP \(bu 2 \fBsendSticker(bufferOrPath)\fR - Send sticker from buffer or file .IP \(bu 2 \fBgetPlugin(name)\fR - Access another plugin's public API .IP \(bu 2 \fBchat\fR - Chat info: \fBid\fR, \fBname\fR, \fBisGroup\fR .IP \(bu 2 \fBlog.info(...), log.warn(...), log.error(...)\fR - Logging methods .RE .SH EXAMPLES .SS Simple Command .nf import { CMD_PREFIX } from "../../config.js"; export default async function ({ msg, api }) { if (!msg.is(CMD_PREFIX + "hi")) return; await msg.reply("Hello! 👋"); } .fi .SS Command with Arguments .nf import { CMD_PREFIX } from "../../config.js"; export default async function ({ msg, api }) { if (!msg.is(CMD_PREFIX + "calc")) return; const [, a, op, b] = msg.args; let result; switch (op) { case "+": result = Number(a) + Number(b); break; case "-": result = Number(a) - Number(b); break; default: return msg.reply("Invalid operator!"); } await msg.reply(`Result: ${result}`); } .fi .SS Processing Media .nf import { CMD_PREFIX } from "../../config.js"; export default async function ({ msg, api }) { if (!msg.is(CMD_PREFIX + "echo")) return; if (!msg.hasMedia) { return msg.reply("Send media with the command!"); } const media = await msg.downloadMedia(); await api.sendSticker(media.data); } .fi .SS Exposing API to Other Plugins .nf // Public API for other plugins export const api = { formatDate: (d) => d.toLocaleDateString("en-US"), wait: (ms) => new Promise(r => setTimeout(r, ms)) }; // Normal plugin logic export default async function ({ msg }) { if (msg.is("!ping")) await msg.reply("pong!"); } .fi .PP Used by another plugin: .nf export default async function ({ msg, api }) { const utils = api.getPlugin("utilities"); const date = utils.formatDate(new Date()); await msg.reply(`Today is ${date}`); } .fi .SH TRANSLATIONS Plugins can include their own translations: .PP .nf import { createPluginI18n } from "../../utils/pluginI18n.js"; const { t } = createPluginI18n(import.meta.url); export default async function ({ msg }) { if (!msg.is(CMD_PREFIX + "hello")) return; await msg.reply(t("greeting", { name: msg.senderName })); } .fi .PP Locale file (\fIlocale/en.json\fR): .nf { "greeting": "Hello, {{name}}! 👋" } .fi .PP If the configured locale has no translation file, falls back to \fBen.json\fR. Use \fB{{variable}}\fR syntax for interpolation. .SH ENABLING A PLUGIN Add the plugin folder name to .I manybot.conf R: .PP .nf PLUGINS=[ many, figurinha, my-plugin ] .fi .PP Restart ManyBot to load the plugin. .SH ERROR HANDLING If a plugin throws an error, the kernel automatically disables it. Use try/catch for graceful error handling: .PP .nf export default async function ({ msg, api }) { try { const result = await riskyOperation(); await msg.reply(result); } catch (error) { api.log.error("Plugin error:", error); await msg.reply("Oops! Something went wrong."); } } .fi .SH CONFIGURATION ACCESS Import settings from the main config: .PP .nf import { CMD_PREFIX, CLIENT_ID, CHATS, PLUGINS } from "../../config.js"; // Custom config values also work import { MY_API_KEY } from "../../config.js"; .fi .PP Add custom values to .I manybot.conf R: .nf MY_API_KEY=secret_key_here .fi .SH SEE ALSO .BR manybot (1), .BR manyplug (1), .BR manybot.conf (5) .SH AUTHOR Written by synt-xerror. .SH REPORTING BUGS Report bugs at: https://github.com/synt-xerror/manybot/issues