fca-eryxenx
Unofficial Facebook Messenger Bot API for Node.js NEXCA Engine · Signal Protocol E2EE · sessionGuard · 90+ API Methods · Zero TypeScript
Features • Installation • Quick Start • E2EE • sessionGuard • sendBroadcast • API Reference
Why fca-eryxenx?
- NEXCA Engine — nexca MQTT, E2EE, sessionGuard core integrated
- ST-FCA Native E2EE (messagix binary) — Facebook Labyrinth E2EE via native binary + koffi FFI
- Signal Protocol E2EE (fallback) — pure-JS Signal Protocol fallback if native unavailable
- Full E2EE API — sendMessage, sendMedia, sendReaction, editMessage, unsendMessage, downloadMedia, resolveAttachment
- sessionGuard — appstate corruption and silent logout protection, auto-backup
- sendBroadcast — rate-limited multi-thread broadcast
- Fixed MQTT subscribe race condition — no more "Connection refused: No subscription existed"
-
isActiveClient()guard — stale MQTT client events no longer processed -
connectTimeoutextended — no premature logout on slow networks - autoReconnect — auto-reconnect on connection drop
- GoatBot compatible — all API signatures unchanged (
threadIDoptional etc.) - 90+ API methods — sendMessage, editMessage, setMessageReaction, getThreadInfo and more
ST-FCA Native E2EE — Full Integration
This package merges all E2EE features from ST-FCA into fca-eryxenx (A to Z).
What was merged from ST-FCA
| Module | Description |
|---|---|
src/e2ee/stfca-bridge.js |
Native Labyrinth E2EE bridge — full port of ST-FCA's e2ee.js |
lib/index.mjs |
ESM koffi FFI bridge that loads the native binary |
build/messagix.so |
Linux native binary (Labyrinth E2EE protocol) |
build/messagix.dll |
Windows native binary |
New API methods (auto-registered on every api after login)
// Check if a thread ID is an E2EE JID (contains "@")
api.isE2EEChatJid("61568577897207:69@msgr") // → true
// Connect — tries native messagix binary first, NEXCA pure-JS fallback
await api.connectE2EE();
// Send text to E2EE thread
await api.sendE2EEMessage("61568577897207:69@msgr", "Hello!");
// Send image/video/audio/voice/file/sticker
await api.sendE2EEMedia(jid, "image", fs.readFileSync("./photo.jpg"), {
mimeType: "image/jpeg",
caption: "Photo"
});
// React to E2EE message
await api.sendE2EEReaction(jid, messageID, senderJid, "❤️");
// Edit E2EE message
await api.editE2EEMessage(jid, messageID, "Edited text");
// Unsend E2EE message
await api.unsendE2EEMessage(jid, messageID);
// Download encrypted media attachment
const { data, mimeType } = await api.downloadE2EEMedia({ directPath, mediaKey, mediaSha256, mimeType, mediaType });
// Resolve encrypted attachment to a local HTTP URL
const resolved = await api.resolveE2EEAttachment(attachment);
// Send typing indicator in E2EE thread
await api.sendTypingE2EE("61568577897207:69@msgr", true);
Listen to both E2EE and regular messages
login({ appState }, {}, async (err, api) => {
await api.connectE2EE();
api.listenE2EE((err, event) => {
if (event.type === "e2ee_message") {
// Secret conversation message (isE2EE: true)
api.sendE2EEMessage(event.threadID, "Reply to encrypted msg!");
} else if (event.type === "message") {
// Regular MQTT message
api.sendMessage("Reply!", event.threadID);
}
});
});
Credits
ST-FCA E2EE engine by ST | Sheikh Tamim · github.com/sheikhtamimlover/ST-FCA
Features
- Full Messenger API — messages, reactions, attachments, stickers, polls, pins
- NEXCA MQTT — stable connection, autoReconnect, jitter, isActiveClient guard
- ST-FCA native E2EE — messagix binary (Labyrinth) + Signal Protocol fallback
- Full E2EE send/receive — text, media, reactions, edits, unsend, typing, receipts
- sessionGuard — appstate auto-save, corruption guard, .bak backup
- sendBroadcast — parallel/sequential multi-thread sending with rate limit
- MessengerBot — Discord.js/Telegraf style (.command, .hears, .launch)
- createFcaClient — namespaced facade (client.messages, client.threads etc.)
- GoatBot / Mirai compatible — drop-in replacement
Installation
npm install fca-eryxenx
Node.js >= 18 required.
Quick Start
Classic (GoatBot compatible)
const login = require("fca-eryxenx");
login({ appState: require("./account.json") }, { listenEvents: true }, (err, api) => {
if (err) throw err;
api.sessionGuard("./account.json", {
interval: 3 * 60 * 1000,
debounce: 30 * 1000
});
api.listenMqtt((err, event) => {
if (err) throw err;
if (event.type === "message") api.sendMessage(event.body, event.threadID);
});
});
With E2EE (regular + encrypted threads)
login({ appState: require("./account.json") }, { listenEvents: true }, async (err, api) => {
if (err) throw err;
api.sessionGuard("./account.json");
await api.connectE2EE();
api.listenE2EE((err, event) => {
if (err) throw err;
if (event.type === "message") {
if (event.isE2EE) {
api.e2ee.sendMessage(event.threadID, "Got your encrypted message!");
} else {
api.sendMessage("Got it!", event.threadID);
}
}
});
});
GoatBot login.js
const login = require("fca-eryxenx");
login({ appState }, options, async (err, api) => {
if (err) return;
api.sessionGuard(path.join(process.cwd(), "account.txt"), {
interval: 3 * 60 * 1000,
debounce: 30 * 1000
});
try { await api.connectE2EE(); } catch (e) {}
api.listenMqtt(callback);
});
E2EE — Encrypted Conversations
Uses Facebook's real Signal Protocol infrastructure — same as the official Messenger app.
Setup
await api.connectE2EE();
// Auto-creates .nexca/e2ee_device.json
console.log(api.e2ee.isConnected()); // true
Listen (regular + E2EE combined)
api.listenE2EE((err, event) => {
if (event.type === "message") {
if (event.isE2EE) {
api.e2ee.sendMessage(event.threadID, "Encrypted reply!");
} else {
api.sendMessage("Normal reply!", event.threadID);
}
}
});
E2EE Methods
await api.e2ee.sendMessage(threadID, "Hello!");
await api.e2ee.sendMessage(threadID, { body: "Photo!", attachment: fs.createReadStream("photo.jpg") });
await api.e2ee.sendReaction(threadID, messageID, "❤️");
await api.e2ee.sendTyping(threadID, true);
await api.e2ee.unsendMessage(messageID, threadID);
await api.e2ee.editMessage(threadID, messageID, "Updated!");
api.e2ee.isConnected();
await api.e2ee.disconnect();
sessionGuard
Protects your appstate from corruption and silent logouts.
api.sessionGuard("./account.json");
// Custom timing
api.sessionGuard("./account.json", {
interval: 3 * 60 * 1000,
debounce: 30 * 1000
});
What it does:
- Auto-saves appstate every N minutes
- Saves after every successful sendMessage (debounced)
- Corruption guard — never overwrites a larger appstate with a smaller one
- Auto-backup — writes
.bakbefore every overwrite
api.saveSession(); // force save now
api.restoreSessionBackup(); // restore from .bak
api.stopSessionGuard(); // stop the timer
sendBroadcast
Rate-limited multi-thread broadcast.
const result = await api.sendBroadcast(
"Hello everyone!",
["THREAD_1", "THREAD_2", "THREAD_3"],
{
delay: 2000,
parallel: 2,
onEach: (err, info, id) => {
console.log(err ? "Failed: " + id : "Sent: " + id);
}
}
);
console.log(result.sent.length + "/" + result.total + " delivered");
MessengerBot
Discord.js/Telegraf style high-level bot class.
const { createMessengerBot } = require("fca-eryxenx");
const bot = await createMessengerBot(
{ appState: require("./account.json") },
{ commandPrefix: "/", stopOnSignals: true }
);
bot.command("ping", async ctx => await ctx.replyAsync("pong 🏓"));
bot.hears(/hello/i, async ctx => await ctx.replyAsync("Hi! 👋"));
bot.on("messageCreate", event => console.log(event.body));
await bot.launch({ stopOnSignals: true });
createFcaClient
Namespaced facade grouping all API methods by domain.
const { createFcaClient } = require("fca-eryxenx");
const client = createFcaClient(api);
await client.messages.send("Hello!", threadID);
await client.messages.react("❤️", messageID, threadID);
await client.threads.getInfo(threadID);
await client.users.getInfo(userID);
await client.account.refreshDtsg();
API Reference
Sending Messages
api.sendMessage("Hello!", threadID);
api.sendMessage({ body: "Photo!", attachment: fs.createReadStream("photo.jpg") }, threadID);
api.sendMessage({ body: "Hey @John", mentions: [{ id: "uid", tag: "@John", fromIndex: 4 }] }, threadID);
api.sendMessage({ sticker: "369239263222822" }, threadID);
api.sendMessage({ location: { latitude: 23.8, longitude: 90.4, current: true } }, threadID);
api.sendBroadcast("msg", ["tid1", "tid2"], { delay: 2000 });
api.sendGif("https://media.giphy.com/xyz.gif", threadID);
api.sendLocation(23.8, 90.4, threadID);
api.sendImage("./photo.jpg", threadID, "caption");
api.sendVideo("./video.mp4", threadID);
api.sendAudio("./voice.ogg", threadID);
api.sendFile("./doc.pdf", threadID);
api.shareLink("https://github.com", threadID, "Check this!");
api.shareContact("Meet my friend!", userID, threadID);
Message Actions
api.editMessage("Updated text", messageID);
api.unsendMessage(messageID);
api.deleteMessage([messageID]);
api.setMessageReaction("😍", messageID, threadID); // threadID optional
api.setMessageReaction("", messageID); // remove reaction
api.getMessage(threadID, messageID);
api.forwardAttachment(attachmentID, [userID]);
api.uploadAttachment([fs.createReadStream("photo.jpg")]);
Read Receipts & Typing
api.markAsRead(threadID);
api.markAsReadAll();
api.markAsDelivered(threadID, messageID);
api.markAsSeen();
api.sendTypingIndicator(threadID, true);
Thread Management
api.getThreadInfo(threadID);
api.getThreadList(10, null, ["INBOX"]);
api.getThreadHistory(threadID, 20);
api.createGroup("Hey!", ["uid1", "uid2"]);
api.deleteThread(threadID);
api.muteThread(threadID, 3600);
api.changeArchivedStatus(threadID, true);
api.handleMessageRequest(threadID, true);
api.searchForThread("query");
Thread Customization
api.setTitle("New Name", threadID);
api.changeThreadColor("#0084FF", threadID);
api.changeThreadEmoji("🔥", threadID);
api.changeNickname("The Boss", threadID, userID);
api.changeGroupImage(fs.createReadStream("group.jpg"), threadID);
api.changeAdminStatus(threadID, userID, true);
api.addUserToGroup(userID, threadID);
api.removeUserFromGroup(userID, threadID);
api.createPoll("Question?", threadID, { "Yes": false, "No": false });
api.pinMessage(messageID, threadID);
api.unpinMessage(messageID, threadID);
User Info
api.getUserInfo(userID);
api.getUserID("John Doe", callback);
api.getUID("https://facebook.com/zuck");
api.getFriendsList();
api.getAvatarUser(userID);
api.getProfileInfo(userID);
api.getPublicData(userID);
api.sendFriendRequest(userID);
api.handleFriendRequest(userID, true);
api.changeBlockedStatus(userID, true);
api.followUser(userID);
api.unfollowUser(userID);
api.unfriend(userID);
Social
api.reactToPost(postID, "love");
api.reactToComment(commentID, "haha");
api.postComment(postID, "Great post!");
api.sharePost(postID, "Check this!");
Account & Config
api.getCurrentUserID();
api.getAppState();
api.setOptions({ listenTyping: true });
api.logout();
api.refreshFb_dtsg();
api.addExternalModule("myFunc", (defaultFuncs, api, ctx) => {
return function(text, threadID) {
return api.sendMessage("[BOT] " + text, threadID);
};
});
HTTP Utilities
api.httpGet(url, params, callback);
api.httpPost(url, form, callback);
api.httpPostFormData(url, form, callback);
api.uploadImageToImgbb(imageUrl);
Login Options
| Option | Type | Default | Description |
|---|---|---|---|
selfListen |
boolean | false | Receive your own sent messages |
listenEvents |
boolean | true | Receive thread/group events |
listenTyping |
boolean | false | Receive typing indicator events |
updatePresence |
boolean | false | Receive online/offline presence events |
autoMarkDelivery |
boolean | false | Auto-mark incoming messages as delivered |
autoMarkRead |
boolean | false | Auto-mark threads as read |
autoReconnect |
boolean | true | Auto-reconnect MQTT on disconnect |
online |
boolean | false | Appear as online to others |
emitReady |
boolean | false | Emit ready event when MQTT connected |
proxy |
string | — | HTTP proxy URL |
userAgent |
string | Safari UA | Override HTTP User-Agent |
License
MIT License
fca-eryxenx by EryXenX (Mohammad Akash) NEXCA Engine by Deku — MIT License
Unauthorized copying or redistribution without credit is prohibited.
Made with by EryXenX