\1\n
ISSUE 02 · 2026 OPEN SOURCE PYTHON ≥ 3.10

Một thư viện chat
cho Facebook, hiện đại hơn.
A chat library
for Facebook, reimagined.

fbchat-v2 là thư viện mã nguồn mở để tự động hóa tin nhắn, quản lý nhóm và lắng nghe sự kiện Messenger thời gian thực — không cần Graph API. fbchat-v2 is an open-source library for automating Messenger conversations, managing group threads, and listening to real-time events — no Graph API required.

GitHub · Mục tiêu sao GitHub · Star Goal
0%
0 / 200 stars Cập nhật thời gian thực Realtime update
E2EE READY
Từ 11/2024, Facebook bật Mã hoá đầu-cuối mặc định cho Messenger. Thư viện đã hỗ trợ giải mã Secret Conversations từ 12/05/2026 qua module _listening_e2ee (bridge Go dựa trên Signal Protocol). Đọc/gửi được cả tin nhắn 1-1 lẫn nhóm ở chế độ E2EE. Since Nov 2024, Facebook enables end-to-end encryption by default on Messenger. The library has supported Secret Conversation decryption since 24/03/2026 via the _listening_e2ee module (Go bridge on Signal Protocol). Both 1-on-1 and group E2EE messages can be read and sent.
API không chính thứcUnofficial API
Đây không phải API chính thức. Đăng nhập bằng cookie/password vi phạm TOS Facebook và có nguy cơ checkpoint. Tự chịu rủi ro khi sử dụng. Not an official API. Logging in with cookies/passwords violates Facebook TOS and may trigger checkpoints. Use at your own risk.

Vì sao chọn fbchat-v2Why choose fbchat-v2

Why fbchat-v2

Không như Graph API chỉ hoạt động với Fanpage,Unlike Graph API which only works with Fanpages, fbchat-v2 tích hợp sâu qua tài khoản cá nhân.integrates deeply through personal accounts.

Unlike the Graph API limited to fanpages, fbchat-v2 integrates deeply via user accounts.

/ 01
Truy cập trực tiếpDirect Access
Đăng nhập bằng tài khoản thật, không giới hạn như page.Login with real accounts — no page restrictions.
/ 02
Nhắn tin nâng caoAdvanced Messaging
Gửi text, ảnh, video, sticker, thả react, thu hồi.Text, images, videos, stickers, reactions, retractions.
/ 03
Quản lý nhómGroup Management
Đổi tên, emoji, biệt danh, quyền admin bằng script.Rename, emojis, nicknames, admin roles programmatically.
/ 04
Thời gian thựcReal-time
MQTT qua WebSocket, nhận tin tức thì.MQTT over WebSocket, instant delivery.
/ 05
GraphQL APIGraphQL API
Tương tác mạnh mẽ với Facebook qua cấu trúc GraphQL.Interact with Facebook natively via its robust GraphQL structure.
/ 06
Giải mã E2EEE2EE Decryption
Hỗ trợ mã hóa đầu cuối, đọc và gửi tin nhắn bảo mật.Support for End-to-End Encrypted (E2EE) messages.

Kiến trúc ba tầngThree-Layer Architecture

Three-Layer Architecture

Mã nguồn được phân chia thành 3 lớp rõ ràng để dễ bảo trì.The source code is divided into 3 clear layers for easy maintenance.

The project is split into three clear layers for maintainability.

Base
_core
Xác thực, quản lý session, tạo payload HTTP.Authentication, session, HTTP payload crafting.
Business
_features
Tác vụ profile, tìm kiếm, you bè, quản trị thread.Profile ops, search, friends, thread admin.
Transport
_messaging
Gửi, upload, reaction và MQTT listener.Send, upload, reactions and MQTT listener.
02 / INSTALLATION

Cài đặt và lựa chọn namespaceInstallation & Namespace Selection

Chọn một trong hai phương thức cài đặt dưới đây. Gói PyPI sử dụng namespace fbchat_v2; bản chạy trực tiếp từ mã nguồn sử dụng các package cấp cao nhất trong src/.Choose one of the two installation methods below. The PyPI package uses the fbchat_v2 namespace; running directly from source uses top-level packages in src/.

LƯU Ý NAMESPACENAMESPACE NOTE

PyPI: from fbchat_v2._core...

Mã nguồn:Source: from _core... sau khi thêm src vào đường dẫn import. Một ứng dụng nên sử dụng thống nhất một kiểu import.from _core... after adding src to the import path. An application should consistently use one import style.

python -m venv .venv

# Windows PowerShell
.venv\Scripts\Activate.ps1

# Linux / macOS
source .venv/bin/activate

python -m pip install --upgrade pip
python -m pip install "fbchat-v2==2.2.0"
from fbchat_v2._core._session import dataGetHome
from fbchat_v2._messaging._send import api as SendAPI

Yêu cầu hệ thốngSystem Requirements

Thành phầnComponentTối thiểuMinimumKhi nào cầnWhen neededGhi chúNotes
Python3.10Luôn luônAlwaysKhuyến nghị 3.11 or 3.12Recommended 3.11 or 3.12
httpx0.27Luôn luônAlwaysTransport async chínhMain async transport
paho-mqtt1.6.1Listener / LS taskVòng lặp blocking được đặt sau boundary asyncBlocking loop placed behind the async boundary
Go1.26.5 theo go.modChỉ khi tự build bridgeOnly when building bridge manuallyKhông cần nếu dùng binary release phù hợpNot needed if using suitable binary release
GitBản hiện hànhCurrent versionClone source / submoduleBridge phụ thuộcDependent bridgebridge-e2ee/meta

Kiểm tra khả năng importCheck Import Capability

import asyncio

from fbchat_v2._core._session import dataGetHome
from fbchat_v2._messaging._send import api as SendAPI


async def main() -> None:
    assert callable(dataGetHome)
    assert callable(SendAPI().send)
    print("fbchat-v2 2.2.0 import OK")


asyncio.run(main())
03 / EXECUTION MODEL

Mô hình thực thi bất đồng bộAsynchronous Execution Model

API v2.2.0 được thiết kế theo hướng async-first. Khi một coroutine được gọi mà không có await, thao tác tương ứng chưa được thực thi và giá trị trả về chỉ là một đối tượng coroutine.API v2.2.0 is designed with an async-first approach. When a coroutine is called without await, the corresponding operation has not been executed, and the returned value is just a coroutine object.

Sai
data_fb = dataGetHome(cookie)
result = SendAPI().send(data_fb, "hello", user_id)
listener.connect_mqtt()

Kết quả là một đối tượng coroutine và có thể phát sinh cảnh báo was never awaited hoặc lỗi object has no attribute 'get'.The result is a coroutine object and may raise a 'was never awaited' warning or 'object has no attribute get' error.

ĐúngTrue
data_fb = await dataGetHome(cookie)
result = await SendAPI().send(data_fb, "hello", user_id)
task = asyncio.create_task(listener.connect_mqtt())

Các thao tác ngắn được await trực tiếp; listener chạy dài hạn được quản lý bằng một task.Short operations are awaited directly; long-running listeners are managed by a task.

Điểm vào của ứng dụng CLICLI Application Entry Point

import asyncio


async def main() -> None:
    # Entire async workflow goes here.
    ...


if __name__ == "__main__":
    asyncio.run(main())

Khi ứng dụng đã có event loopWhen App Already Has an Event Loop

FastAPI, Jupyter, Discord bot hoặc framework async đã sở hữu event loop. Trong coroutine của framework, gọi await trực tiếp. Không lồng asyncio.run().FastAPI, Jupyter, Discord bot or async frameworks already have an event loop. Inside the framework's coroutine, call await directly. Do not nest asyncio.run().

Chạy đồng thời có kiểm soátControlled Concurrency

import asyncio
import httpx

from fbchat_v2._features._facebook import _notification, _search


async with httpx.AsyncClient(timeout=30) as client:
    async with asyncio.TaskGroup() as group:
        notification_task = group.create_task(
            _notification.func(data_fb, client=client)
        )
        search_task = group.create_task(
            _search.func(data_fb, "m008v", client=client)
        )

    notifications = notification_task.result()
    users = search_task.result()

Python 3.10 chưa hỗ trợ TaskGroup; hãy sử dụng asyncio.gather(). Luôn thiết lập timeout tại ranh giới tác vụ và không bỏ qua CancelledError.Python 3.10 does not support TaskGroup; use asyncio.gather(). Always configure timeouts at task boundaries and do not ignore CancelledError.

04 / SESSION

Từ cookie đến dataFBFrom cookie to dataFB

dataGetHome() truy cập trang chủ Facebook, trích xuất các token phiên và trả về cấu trúc dữ liệu dùng chung cho các module còn lại.dataGetHome() accesses the Facebook homepage, extracts session tokens, and returns a shared data structure for the remaining modules.

import asyncio

from fbchat_v2._core._session import dataGetHome


async def main() -> None:
    cookie = "c_user=...; xs=...; fr=...; datr=...;"
    data_fb = await dataGetHome(cookie)
    if data_fb is None:
        raise RuntimeError("Cookie expired or Facebook changed homepage token.")

    required = {
        "FacebookID",
        "fb_dtsg",
        "jazoest",
        "sessionID",
        "clientRevision",
        "cookieFacebook",
    }
    missing = [key for key in required if not data_fb.get(key)]
    if missing:
        raise RuntimeError(f"dataFB missing field: {', '.join(missing)}")


asyncio.run(main())

Hợp đồng dataFBdataFB Contract

FieldVai tròRoleCó nhạy cảm?Is sensitive?
FacebookIDID tài khoản hiện hànhCurrent account IDYes
fb_dtsg, jazoestToken chống giả mạo request nội bộInternal request anti-forgery tokenRất nhạy cảmVery sensitive
sessionIDID sinh cho request lifecycleYes
clientRevisionRevision Facebook clientÍt hơn, nhưng vẫn không nên log toàn objectLess, but still shouldn't log entire objects
cookieFacebookCookie gốc dùng cho HTTP và bridgeBase cookie used for HTTP and bridgeTuyệt đối bí mậtStrictly confidential

Lưu trữ phiên cục bộLocal session storage

from pathlib import Path
from fbchat_v2._core._storage import FileSessionStorage

storage = FileSessionStorage(Path(".secrets/facebook-session.json"))
storage.save(cookie)
cookie = storage.load()
storage.clear()
THÔNG TIN BÍ MẬTSECRET INFORMATION

Không lưu cookie thật trong , mã nguồn, ảnh chụp màn hình hoặc nhật ký CI. Tệp lưu trữ cục bộ chỉ tách thông tin bí mật khỏi mã nguồn và không tự động mã hóa nội dung.Do not store actual cookies in , source code, screenshots, or CI logs. Local storage files only separate secrets from source code and do not automatically encrypt contents.Không lưu cookie thật trongDo not store real cookies in config.example.json, mã nguồn, ảnh chụp màn hình hoặc nhật ký CI. Tệp lưu trữ cục bộ chỉ tách thông tin bí mật khỏi mã nguồn và không tự động mã hóa nội dung., source code, screenshots or CI logs. Local storage files only separate secrets from source code and do not automatically encrypt contents.

05 / HTTP TRANSPORT

Tái sử dụng httpx.AsyncClientReusing httpx.AsyncClient

Một HTTP client được duy trì trong suốt vòng đời ứng dụng giúp tái sử dụng kết nối TCP/TLS, thống nhất cấu hình timeout và hỗ trợ kiểm thử bằng transport giả lập.A single HTTP client maintained throughout the app lifecycle helps reuse TCP/TLS connections, unifies timeout configurations, and supports testing with mock transports.

import asyncio
import httpx

from fbchat_v2._features._facebook import _notification, _search


timeout = httpx.Timeout(30.0, connect=10.0)
limits = httpx.Limits(max_connections=20, max_keepalive_connections=10)

async with httpx.AsyncClient(
    timeout=timeout,
    limits=limits,
    follow_redirects=True,
) as client:
    notifications, users = await asyncio.gather(
        _notification.func(data_fb, client=client),
        _search.func(data_fb, "Minh", client=client),
    )

Bên gọi truyền client=Caller passes client=

Bên gọi sở hữu client và chịu trách nhiệm đóng tài nguyên. Phương thức này phù hợp với bot, worker và web service hoạt động dài hạn.The caller owns the client and is responsible for closing resources. This method is suitable for long-running bots, workers and web services.

Không truyền client=Without Passing client=

Helper tự tạo và đóng client cho từng lần gọi. Phương thức này phù hợp với script ngắn nhưng làm tăng chi phí thiết lập kết nối khi gọi nhiều API liên tiếp.The helper creates and closes the client for each call. This method is suitable for short scripts but increases connection setup costs when calling multiple APIs consecutively.

Timeout tại ranh giới tác vụTimeout at Task Boundaries

try:
    result = await asyncio.wait_for(
        _search.func(data_fb, "query", client=client),
        timeout=20,
    )
except asyncio.TimeoutError:
    result = {"error": 1, "messages": "Search timed out."}
  • Không chia sẻ một client giữa nhiều event loop ở các thread khác nhau.Do not share one client across multiple event loops in different threads.
  • Không sử dụng client sau khi thoát .Do not use client after exiting .Không sử dụng client sau khi thoátDo not use client after exiting async with.
  • Không tắt xác minh TLS để chữa lỗi chứng chỉ. Sửa CA/proxy của môi trường.Do not disable TLS verification to fix certificate errors. Fix the environment's CA/proxy.
  • Không thử lại vô hạn đối với các request làm thay đổi trạng thái, chẳng hạn đăng bài hoặc gửi tin nhắn.Do not retry indefinitely for state-changing requests, such as posting or sending messages.
06 / SEND

Gửi tin nhắn thườngSending Normal Messages

hỗ trợ gửi tới người dùng, nhóm, nhiều người nhận, trả lời tin nhắn và tệp đính kèm. Mỗi lần gọi tạo form riêng nên có thể thực thi đồng thời.supports sending to users, groups, multiple recipients, replying to messages, and attachments. Each call creates a separate form so they can be executed concurrently.SendAPI().send()

await SendAPI().send(
    dataFB,
    contentSend,
    threadID,
    typeAttachment=None,
    attachmentID=None,
    typeChat=None,
    replyMessage=None,
    messageID=None,
    client=None,
)
Tham sốParametersKiểuTypeQuy tắcRule
contentSendstr | intUse chuỗi rỗng khi chỉ gửi attachmentUse empty string when only sending attachments
threadIDID or list IDID or list of IDsList chỉ hợp lệ khi typeChat="user"List is only valid when typeChat="user"
typeChat"user" | NoneUser direct or group threadUser direct or group thread
typeAttachmentgif, image, video, file, audioPhải đi cùng attachmentIDMust accompany attachmentID
replyMessageboolKhi true phải có messageIDWhen true, messageID is required
clienthttpx.AsyncClientOptional, truyền bằng keywordOptional, passed by keyword
User Group Multiple users Reply
result = await SendAPI().send(
    data_fb,
    "Xin chào",
    threadID="100012345678",
    typeChat="user",
    client=client,
)
result = await SendAPI().send( data_fb, "Hello", threadID="100012345678", typeChat="user", client=client, )

Xử lý kết quả trả vềHandling Responses

if not isinstance(result, dict):
    raise TypeError("Send API did not return dict.")
if result.get("error"):
    payload = result.get("payload") or {}
    raise RuntimeError(
        payload.get("error-description") or "Facebook rejected message sending."
    )

message_id = (result.get("payload") or {}).get("messageID")
07 / ATTACHMENTS

Tải lên và gửi tệp đính kèmUploading & Sending Attachments

Tải tệp và gửi tin nhắn là hai bước độc lập. Chỉ trong metadata hợp lệ mới được chuyển sang sender; không thể thay thế giá trị này.Uploading files and sending messages are independent steps. Only a valid in metadata is passed to the sender; cannot replace this value.Tải tệp và gửi tin nhắn là hai bước độc lập. ChỉDownloading files and sending messages are two independent steps. Only attachmentID trong metadata hợp lệ mới được chuyển sang sender;in valid metadata will be passed to sender; uploadID không thể thay thế giá trị này.cannot replace this value.

1
Kiểm tra đường dẫnCheck path

Module từ chối danh sách rỗng và đường dẫn không tồn tại trước khi gửi request.The module rejects empty lists and non-existent paths before sending the request.

2
Tải multipartMultipart upload

Truyền httpx.AsyncClient dùng chung để request được thực thi bất đồng bộ.Pass a shared httpx.AsyncClient so the request executes asynchronously.

3
Kiểm tra metadataCheck metadata

Kết quả hợp lệ phải có attachmentIDtypeAttachment.Valid results must have attachmentID and typeAttachment.

4
Gửi tin nhắnSend message

Truyền đúng loại tệp và ID đính kèm sang .Pass the correct file type and attachment ID to .Truyền đúng loại tệp và ID đính kèm sangPass the correct file type and attachment ID to SendAPI.

from fbchat_v2._messaging import _attachments
from fbchat_v2._messaging._send import api as SendAPI


uploaded = await _attachments.func(
    "photo.jpg",
    data_fb,
    client=client,
    include_error=True,
)
if not uploaded or not uploaded.get("attachmentID"):
    raise RuntimeError(f"Upload failed: {uploaded}")

result = await SendAPI().send(
    data_fb,
    "Attached image",
    threadID="100012345678",
    typeChat="user",
    typeAttachment=uploaded["typeAttachment"],
    attachmentID=uploaded["attachmentID"],
    client=client,
)

Cấu trúc kết quả thành côngSuccess Result Structure

{
    "attachmentID": "123...",
    "attachmentUrl": "https://...",
    "videoDuration": None,
    "attachmentType": "image/jpeg",
    "typeAttachment": "image",
}

Tải lên nhiều tệpUploading Multiple Files

Parser hiện trả về phần tử metadata đầu tiên và không cung cấp danh sách tương ứng với toàn bộ đường dẫn. Quy trình đáng tin cậy là tải từng tệp, kiểm tra từng kết quả rồi truyền danh sách ID:The parser currently returns the first metadata element and does not provide a list corresponding to the entire path. A reliable process is to upload each file, check each result, and then pass the ID list:

attachment_ids = []
for path in ["a.jpg", "b.jpg"]:
    item = await _attachments.func(path, data_fb, client=client, include_error=True)
    if not item or not item.get("attachmentID"):
        raise RuntimeError(f"Could not upload {path}: {item}")
    attachment_ids.append(item["attachmentID"])

await SendAPI().send(
    data_fb,
    "Album",
    threadID=user_id,
    typeChat="user",
    typeAttachment="image",
    attachmentID=attachment_ids,
    client=client,
)
YÊU CẦU BỊ TỪ CHỐIREQUEST REJECTED

metadata: {"0": null} hoặc mã lỗi 1357054 cho biết máy chủ không trả về metadata của tệp đính kèm. Hãy kiểm tra phiên đăng nhập, MIME, tệp và endpoint. Bật include_error=True để nhận phần tóm tắt lỗi và trích đoạn phản hồi đã được giới hạn độ dài.metadata: {"0": null} or error code 1357054 indicates the server did not return attachment metadata. Please check login session, MIME, file, and endpoint. Enable include_error=True to receive an error summary and length-limited response excerpt.

08 / REGULAR LISTENER

Listener MQTT thườngNormal MQTT Listener

Listener này xử lý sự kiện thường và một số hội thoại nhóm. Đối với hội thoại cá nhân E2EE, hãy sử dụng listener dựa trên bridge.This listener handles normal events and some group threads. For 1-on-1 E2EE threads, use the bridge-based listener.

import asyncio

from fbchat_v2._messaging._listening import listeningEvent


listener = listeningEvent(data_fb, message_queue_maxsize=1000)
listener_task = asyncio.create_task(
    listener.connect_mqtt(),
    name="fbchat-mqtt-listener",
)

try:
    while True:
        if listener_task.done():
            listener_task.result()

        event = await listener.get_message(timeout=30)
        if event is None:
            continue
        print(event["body"], event["messageID"])
finally:
    await listener.disconnect()
    await listener_task
MethodMục đíchPurposeLưu ýNote
get_last_seq_id()Lấy sequence ID ban đầuGet initial sequence IDAsync
connect_mqtt()Chạy reconnect loopRun reconnect loopTạo task vì chạy dài hạnCreate a task for long-running operation
get_message(timeout)Consume event từ queueConsume event from queueTrả khi timeoutReturns on timeoutTrảReturns None khi timeout
disconnect()Dừng clientStop clientGọi trongCall insidefinally

Cấu trúc sự kiện đã chuẩn hóaStandardized Event Structure

{
    "body": "ping",
    "timestamp": 1710000000000,
    "userID": "1000...",
    "messageID": "mid.$...",
    "replyToID": "thread-id",
    "type": "thread",
    "attachments": {"id": 0, "url": None},
    "mentions": [],
}

Hàng đợi có giới hạn và loại bỏ sự kiện cũ nhất khi đầy. Theo dõi để phát hiện consumer xử lý chậm. Không nên thăm dò trong ứng dụng mới vì đây chỉ là ảnh chụp trạng thái cuối cùng.Bounded queue that drops the oldest events when full. Monitor to detect slow consumers. Do not poll in new applications as this is only a snapshot of the final state.Hàng đợi có giới hạn và loại bỏ sự kiện cũ nhất khi đầy. Theo dõiThe queue is bounded and drops the oldest event when full. Monitor listener.droppedMessages để phát hiện consumer xử lý chậm. Không nên thăm dòto detect slow-processing consumers. You should not poll bodyResults trong ứng dụng mới vì đây chỉ là ảnh chụp trạng thái cuối cùng.in new apps because this is only a snapshot of the final state.

09 / E2EE SETUP

Cài bridge E2EESetup E2EE Bridge

Python wrapper khởi chạy tệp thực thi fbchat-bridge-e2ee. Có thể sử dụng tệp dựng sẵn từ GitHub Release hoặc tự biên dịch từ mã nguồn.The Python wrapper launches the fbchat-bridge-e2ee executable. You can use pre-built files from GitHub Release or compile it from source.

Phương thức 1 - sử dụng binary phát hành sẵnMethod 1 - Using Pre-built Binaries

Nền tảngPlatformAsset
Windows x64fbchat-bridge-e2ee-windows-amd64.exe
Linux x64fbchat-bridge-e2ee-linux-amd64
Linux ARM64fbchat-bridge-e2ee-linux-arm64
macOS Intelfbchat-bridge-e2ee-darwin-amd64
macOS Apple Siliconfbchat-bridge-e2ee-darwin-arm64

Tải tệp phù hợp từ GitHub Releases, đặt vào thư mục build/ hoặc khai báo đường dẫn tuyệt đối:Download suitable files from GitHub Releases, put them in build/ directory or declare absolute path:

# Windows PowerShell
$env:FBCHAT_E2EE_BIN = "C:\path\to\fbchat-bridge-e2ee-windows-amd64.exe"
# Linux / macOS
chmod +x ./fbchat-bridge-e2ee-linux-amd64
export FBCHAT_E2EE_BIN=/absolute/path/fbchat-bridge-e2ee-linux-amd64

Phương thức 2 - biên dịch từ mã nguồnMethod 2 - Compile from Source

git submodule update --init --recursive bridge-e2ee/meta
Set-Location bridge-e2ee
go mod download
New-Item -ItemType Directory -Force ..\build | Out-Null
go build -ldflags="-s -w" -o ..\build\fbchat-bridge-e2ee.exe .
Set-Location ..
.\build\fbchat-bridge-e2ee.exe --help

Thứ tự xác định binaryBinary resolution order

  1. truyền vào constructor.pass to constructor.binary_path=
  2. Biến môi trường FBCHAT_E2EE_BIN.Environment variable FBCHAT_E2EE_BIN.
  3. Đường dẫn mặc định trong build/.Default path in build/.
  4. Tự động tải tệp GitHub Release phù hợp nếu đường dẫn mặc định chưa tồn tại.Automatically download the suitable GitHub Release file if the default path does not exist.
TRẠNG THÁI THIẾT BỊDEVICE STATUS

e2ee_memory_only=True giữ trạng thái thiết bị trong RAM. Khi lưu trạng thái bằng device_path, cần bảo vệ tệp này như thông tin xác thực vì nó đại diện cho thiết bị E2EE đã được ghép nối.e2ee_memory_only=True keeps the device state in RAM. When saving state using device_path, this file must be protected like credentials because it represents the paired E2EE device.

10 / E2EE LISTENER

Vòng đời listener E2EEE2EE Listener Lifecycle

Đăng ký callback trước khi khởi động, chạy listener bằng một task, chờ hoàn tất handshake trong worker thread, xử lý sự kiện qua hàng đợi và dừng bridge trong khối .Register callbacks before starting, run listener as a task, wait for handshake completion in worker thread, handle events via queue, and stop bridge in block.Đăng ký callback trước khi khởi động, chạy listener bằng một task, chờ hoàn tất handshake trong worker thread, xử lý sự kiện qua hàng đợi và dừng bridge trong khốiRegister callback before starting, run listener as a task, wait for handshake completion in worker thread, process events via queue and stop bridge in block finally.

import asyncio
import contextlib

from fbchat_v2._messaging._listening_e2ee import listeningE2EEEvent


async def run_e2ee(data_fb: dict) -> None:
    listener = listeningE2EEEvent(
        data_fb,
        log_level="none",
        e2ee_memory_only=True,
        enable_e2ee=True,
    )
    loop = asyncio.get_running_loop()
    events: asyncio.Queue[dict] = asyncio.Queue(maxsize=1000)

    def enqueue(event: dict) -> None:
        if events.full():
            with contextlib.suppress(asyncio.QueueEmpty):
                events.get_nowait()
        events.put_nowait(event)

    listener.on_message(
        lambda event: loop.call_soon_threadsafe(enqueue, event)
    )
    task = asyncio.create_task(
        listener.connect_mqtt(),
        name="fbchat-e2ee-listener",
    )

    try:
        ready = await asyncio.to_thread(
            listener.wait_until_connected,
            90,
            require_e2ee=True,
        )
        if not ready:
            raise TimeoutError("E2EE handshake has not completed.")

        while True:
            if task.done():
                task.result()
            event = await events.get()
            if event.get("type") not in {"e2eeMessage", "message"}:
                continue
            await handle_message(listener, event)
    finally:
        listener.stop()
        try:
            await asyncio.wait_for(task, timeout=5)
        except asyncio.TimeoutError:
            task.cancel()
            with contextlib.suppress(asyncio.CancelledError):
                await task

Các loại sự kiện quan trọngImportant Event Types

TypeÝ nghĩaMeaningỨng dụng nên làm gìWhat the app should do
readyBridge has created clientBridge has created clientStatus recorded; E2EE handshake may not be completeStatus recorded; E2EE handshake may not be complete
e2eeConnectedE2EE đã sẵn sàngE2EE readyAllow sending operationsAllow sending actions
e2eeMessageTin đã giải mãDecrypted messageUse chatJid, senderJid, idUse chatJid, senderJid, id
messageNormal event via bridgeNormal event via bridgeUse threadId, senderIdUse threadId, senderId
errorRequest or bridge errorRequest or bridge errorLog error type but not secretsLog error type but not secrets
bridge_fatalWatchdog has exhausted retriesWatchdog exhausted retriesMark health check failed; do not initialize infinite listenerMark health check as failed; do not initialize infinite listener

Cấu trúc e2eeMessagee2eeMessage Structure

{
    "type": "e2eeMessage",
    "data": {
        "id": "message-id",
        "text": "ping",
        "timestampMs": 1710000000000,
        "senderId": "1000...",
        "threadId": "...",
        "chatJid": "1000...@msgr",
        "senderJid": "1000...@msgr",
        "attachments": [],
        "mentions": [],
    },
}

Gửi và trả lời tin nhắn E2EESending & Replying E2EE Messages

data = event["data"]

result = await listener.send_e2ee_message(
    data["chatJid"],
    "pong",
    reply_to_id=data["id"],
    reply_to_sender_jid=data["senderJid"],
)
RANH GIỚI LUỒNGTHREAD BOUNDARY

on_message() là callback đồng bộ được gọi từ vòng lặp thăm dò của bridge. Không gọi coroutine trực tiếp trong callback này. Hãy chuyển sự kiện về event loop bằng loop.call_soon_threadsafe().on_message() is a synchronous callback invoked from the bridge's polling loop. Do not call coroutines directly in this callback. Push the event back to the event loop using loop.call_soon_threadsafe().

11 / BRIDGE ACTIONS

Thao tác nâng cao qua bridgeAdvanced Operations via Bridge

Sau khi listener sẵn sàng, tạo BridgeActions từ bridge đang hoạt động để tái sử dụng cùng một tiến trình cho các thao tác tiếp theo.After the listener is ready, create BridgeActions from the active bridge to reuse the same process for subsequent operations.

from fbchat_v2._messaging._bridge_actions import BridgeActions

if listener._bridge is None:
    raise RuntimeError("Bridge is not ready.")

actions = BridgeActions(listener._bridge)
Method asyncMục đíchPurpose
edit_message(message_id, new_text)Edit normal messageEdit normal message
unsend_message(message_id)Unsend normal messageUnsend normal message
edit_e2ee_message(chat_jid, message_id, new_text)Edit E2EE messageEdit E2EE message
unsend_e2ee_message(chat_jid, message_id)Unsend E2EE messageUnsend E2EE message
send_typing_indicator(thread_id, is_typing, ...)Typing thườngNormal typing
mark_read(thread_id, watermark_ts)Đánh dấu đã đọcMark as read
send_e2ee_typing(chat_jid, is_typing)Typing E2EE
send_e2ee_audio(chat_jid, data, ...)Send audio bytesSend audio bytes
send_e2ee_image(chat_jid, data, ...)Gửi image bytesSend image bytes
download_media(url)Tải media thường thành bytesDownload normal media as bytes
download_e2ee_media(...)Tải và giải mã media E2EEDownload and decrypt E2EE media

Gửi ảnh E2EE mà không chặn event loopSend E2EE Images Without Blocking Event Loop

from pathlib import Path
import asyncio

image_bytes = await asyncio.to_thread(Path("photo.jpg").read_bytes)
result = await actions.send_e2ee_image(
    chat_jid,
    image_bytes,
    mime_type="image/jpeg",
    caption="Test image",
)

Quản lý và dọn trạng thái typingManage & Cleanup Typing State

await actions.send_e2ee_typing(chat_jid, True)
try:
    response = await build_response(message)
    await listener.send_e2ee_message(chat_jid, response)
finally:
    await actions.send_e2ee_typing(chat_jid, False)

_send_e2ee.api là sender tương thích dành cho tích hợp blocking. Ứng dụng asyncio mới nên tái sử dụng listener và gọi các method async nêu trên._send_e2ee.api is a compatible sender designed for blocking integration. New asyncio applications should reuse the listener and call the async methods mentioned above.

12 / FACEBOOK FEATURES

API nghiệp vụ FacebookFacebook Business API

Phần lớn module tính năng sử dụng hàm công khai tên và phải được gọi bằng . Các tên và alias không còn được cung cấp.Most feature modules use public functions named and must be called with . The names and aliases are no longer provided.Phần lớn module tính năng sử dụng hàm công khai tênMost feature modules use a public function named func và phải được gọi bằngand must be called with await. Các tên. The names func_sync và aliasand aliases func_async không còn được cung cấp.are no longer provided.

_search.func(dataFB, keywordSearch, *, client=None)

Tìm người dùng, loại kết quả trùng theo ID và trả tối đa 5 kết quả. Từ khóa rỗng bị từ chối.Search for users, filter duplicates by ID and return a maximum of 5 results. Empty keywords are rejected.

_notification.func(dataFB, *, client=None)

Trả về dict có key NotificationResults. Cần lấy danh sách từ key này trước khi thực hiện slice.Returns a dict with the key NotificationResults. You need to extract the list from this key before slicing.

_get_user_info.func(dataFB, userID, *, client=None)

Lấy thông tin hồ sơ và trả về dict lỗi khi payload không chứa người dùng yêu cầu.Fetch profile info and return error dict when payload does not contain the requested user.

_changeBio.func(dataFB, newContents, uploadPost=False, *, client=None)

Đổi bio và tùy chọn chia sẻ thay đổi.Bio changed and sharing options changed.

_createPost.func(dataFB, newContents, attachmentID=None, *, client=None)

Đăng bài viết văn bản. Attachment hiện raise để tránh báo thành công không chính xác.Post text status. Attachments currently raise to prevent incorrect success reporting.Đăng bài viết văn bản. Attachment hiện raisePost a text post. Attachment currently raises NotImplementedError để tránh báo thành công không chính xác.to avoid inaccurate success reporting.

_professional.func(dataFB, statusBusiness=None, *, client=None)

Bật hoặc tắt Professional mode; chấp nhận giá trị bool và chuỗi on/off đã chuẩn hóa.Enable or disable Professional mode; accepts bool values and normalized on/off strings.

_blocking.func(dataFB, idUser, choiceInteract, *, client=None)

chỉ nhận hoặc .only accepts or .choiceInteract chỉ nhậnonly accepts block hoặcor unblock.

_registerOnProfile.func(dataFB, newName, newUsername, *, client=None)

Tạo hồ sơ bổ sung; khả năng sử dụng phụ thuộc phạm vi triển khai của Facebook.Create additional profiles; availability depends on Facebook's rollout scope.

_marketplace.createItem(...)

Kiểm tra tên, giá, ảnh, danh mục và tọa độ trước khi gửi request.Check name, price, image, category and coordinates before sending request.

_marketplace.getInformationProductItemMarketPlace(...)

Lấy chi tiết item Marketplace theo product ID.Get Marketplace item details by product ID.

Quy trình sử dụng HTTP client dùng chungWorkflow Using Shared HTTP Client

import httpx

from fbchat_v2._features._facebook import (
    _get_user_info,
    _notification,
    _search,
)


async with httpx.AsyncClient(timeout=30) as client:
    search = await _search.func(data_fb, "m008v", client=client)
    profile = await _get_user_info.func(
        data_fb,
        "100012345678",
        client=client,
    )
    notifications = await _notification.func(data_fb, client=client)
    latest = notifications.get("NotificationResults", [])[:5]
HỢP ĐỒNG KẾT QUẢRESULT CONTRACT

Facebook có thể trả HTTP 200 trong khi payload vẫn chứa , hoặc đối tượng null. Luôn kiểm tra kiểu dữ liệu trả về và , không chỉ dựa vào HTTP status code.Facebook may return HTTP 200 while payload contains , , or null objects. Always check the return data type and , not just the HTTP status code.Facebook có thể trả HTTP 200 trong khi payload vẫn chứaFacebook may return HTTP 200 while the payload still contains error, errors hoặc đối tượng null. Luôn kiểm tra kiểu dữ liệu trả về vàor a null object. Always check the returned data type and result.get("error"), không chỉ dựa vào HTTP status code., not just relying on the HTTP status code.

13 / THREAD FEATURES

Quản trị thread và groupThread & Group Management

Các API thay đổi tên, emoji, biệt danh, quyền quản trị và đọc metadata hội thoại đều được triển khai dưới dạng coroutine.APIs for changing names, emojis, nicknames, administrative privileges, and reading conversation metadata are all implemented as coroutines.

ModulePublic APIGhi chúNotes
_all_thread_dataawait func(dataFB, client=...)Trả dict, không phải listReturns dict, not list
_all_thread_dataawait features(dataGet, threadID, commandUse)Parse payload đã tải trong RAMParse payload loaded in RAM
_changeNameThreadawait func(dataFB, threadID, newNameThread, client=...)Tên rỗng bị rejectEmpty name rejected
_changeEmojiawait func(dataFB, threadID, newEmoji, client=...)Emoji rỗng bị rejectEmpty emojis are rejected
_changeNicknameawait func(dataFB, threadID, idUser, NewNickname, client=...)User phải thuộc threadUser must be in thread
_addAdminawait func(dataFB, threadID, idUser, statusChoice=True, client=...)False là gỡ adminFalse is to remove admin
from fbchat_v2._features._thread import (
    _addAdmin,
    _all_thread_data,
    _changeEmoji,
    _changeNameThread,
    _changeNickname,
)


threads = await _all_thread_data.func(data_fb, client=client)
if threads.get("error") or not threads.get("dataGet"):
    raise RuntimeError(f"Could not fetch thread: {threads}")

info = await _all_thread_data.features(
    threads["dataGet"],
    "thread-id",
    "threadInfomation",
)

await _changeNameThread.func(data_fb, "thread-id", "New name", client=client)
await _changeEmoji.func(data_fb, "thread-id", "🔥", client=client)
await _changeNickname.func(
    data_fb, "thread-id", "user-id", "Nickname", client=client
)
await _addAdmin.func(
    data_fb, "thread-id", "user-id", statusChoice=True, client=client
)

Tên command giữ nguyên cách viết legacy để bảo đảm tương thích. Call site phải sử dụng chính xác giá trị này; một giá trị khác sẽ trả về kết quả lỗi.The command name retains its legacy spelling to ensure compatibility. The call site must use this exact value; any other value will return an error.Tên commandCommand name threadInfomation giữ nguyên cách viết legacy để bảo đảm tương thích. Call site phải sử dụng chính xác giá trị này; một giá trị khác sẽ trả về kết quả lỗi.keeps legacy casing to ensure compatibility. Call sites must use exactly this value; any other value will return an error.

14 / REFERENCE BOT

Bot mẫu src/main.pyExample Bot src/main.py

Bot mẫu minh họa vòng đời ứng dụng và không được thiết kế như một framework hoàn chỉnh cho môi trường production. Ví dụ thể hiện cách kết hợp storage, session, HTTP client, hàng đợi E2EE, bộ định tuyến lệnh và quy trình kết thúc ứng dụng.The example bot illustrates the application lifecycle and is not designed as a complete framework for production environments. The example shows how to combine storage, session, HTTP client, E2EE queue, command router and the application teardown process.

Cấu hình cục bộLocal configuration

{
  "botName": "fbchat-v2 demo bot",
  "prefix": "/",
  "cookies": "c_user=...; xs=...; fr=...; datr=...;",
  "admins": ["100012345678"],
  "version": "0.0.1"
}
1
Đọc và kiểm tra cấu hìnhRead and validate configuration

Kiểm tra prefix, danh sách quản trị viên và cookie cục bộ.Check prefix, admin list and local cookies.

2
Khởi tạo phiênInitialize session

Sử dụng và .Use and .Sử dụngUse FileSessionStorage and await dataGetHome().

3
Mở nhóm kết nối HTTPOpen HTTP connection pool

Tạo một httpx.AsyncClient dùng chung cho các lệnh HTTP.Create a shared httpx.AsyncClient for HTTP commands.

4
Khởi động task E2EEStart E2EE task

Callback chuyển sự kiện vào hàng đợi theo cách an toàn giữa các luồng.Callback pushes events into the queue in a thread-safe manner.

5
Phân phối lệnhCommand dispatching

Loại message ID trùng lặp, bỏ qua tin nhắn do bot gửi và kiểm tra prefix.Filter duplicate message IDs, ignore messages sent by bot and check prefix.

6
Chọn cơ chế phản hồiChoose response mechanism

Khi có chatJid, bot gửi qua E2EE; khi chỉ có threadId, bot sử dụng luồng gửi thường.When chatJid is present, the bot sends via E2EE; when only threadId is present, it uses the standard sending flow.

7
Kết thúc ứng dụngApplication termination

Dừng bridge, chờ listener task hoàn tất và đóng HTTP client.Stop the bridge, wait for the listener task to complete, and close the HTTP client.

Lệnh có sẵnAvailable Commands

/pingĐo latency từ timestamp eventMeasure latency from event timestamp /helpLiệt kê commandList commands /idIn chatJid, threadID, senderJid và messageIDIn chatJid, threadID, senderJid and messageID /echo <text>Reply lại nội dungReply to content /search <query>Tìm user qua HTTP client dùng chungFind user via shared HTTP client /unsendAdmin thu hồi tin E2EE gần nhất của botAdmin unsends bot's latest E2EE message

Thêm lệnh mớiAdding New Commands

# In __init__
self._handlers["hello"] = self._cmd_hello


async def _cmd_hello(self, message: dict, argument: str) -> None:
    sender_id = str(message.get("userID") or "")
    if self.admins and sender_id not in self.admins:
        await self._reply(message, "You do not have permission to use this command.")
        return

    name = argument.strip() or "you"
    await self._reply(message, f"Hello {name}!")

Không thực thi tác vụ CPU-bound hoặc I/O blocking trực tiếp trong handler. Hãy chuyển tác vụ blocking sang , process pool hoặc hàng đợi worker phù hợp.Do not execute CPU-bound or I/O blocking tasks directly in the handler. Move blocking tasks to , process pool, or appropriate worker queues.Không thực thi tác vụ CPU-bound hoặc I/O blocking trực tiếp trong handler. Hãy chuyển tác vụ blocking sangDo not execute CPU-bound or I/O blocking tasks directly in the handler. Move blocking tasks to asyncio.to_thread(), process pool hoặc hàng đợi worker phù hợp., process pool or a suitable worker queue.

15 / QUICK REFERENCE

Bảng tra API asyncAsync API Reference

Bảng dưới đây liệt kê các lời gọi công khai. Helper có hậu tố _blocking là ranh giới tương thích nội bộ và không phải API mặc định cho ứng dụng asyncio.The table below lists public calls. Helpers with the _blocking suffix are internal compatibility boundaries and are not the default API for asyncio applications.

CoreCore

APIResultResult
await dataGetHome(cookie=None, storage=None)dataFB | None
await post_async(request_kwargs, client=None)HTTP response wrapper
await get_async(request_kwargs, client=None)HTTP response wrapper
await loginFacebook(...).main()Login result dict
await GetToken2FA(key2Fa)OTP string or lỗiOTP string or error

Messaging

ModuleAPI chínhMain APIs
_sendawait api().send(...)
_attachmentsawait func(filenames, dataFB, client=None, include_error=False)
_reactionsawait func(dataFB, typeAdded, messageID, emojiChoice, client=None)
_unsendawait func(messageID, dataFB, client=None)
_editMessageawait func(dataFB, messageID, newText)
_message_requestsawait func(dataFB, client=None)
_changeThemeawait listThemes(), findTheme(), changeTheme(), func()
_createNotesawait checkNote(), createNote(), deleteNote(), recreateNote(), func()
_listeningconnect_mqtt(), get_message(), disconnect()
_listening_e2eeconnect_mqtt(), send_message(), send_e2ee_message()

Reaction, chỉnh sửa và thu hồiReaction, Edit & Unsend

from fbchat_v2._messaging import _editMessage, _reactions, _unsend

edited = await _editMessage.func(
    data_fb,
    "mid.$message",
    "New content",
)
reacted = await _reactions.func(
    data_fb,
    "ADD_REACTION",
    "mid.$message",
    "🔥",
    client=client,
)
removed = await _unsend.func(
    "mid.$message",
    data_fb,
    client=client,
)

Theme và Messenger NotesTheme & Messenger Notes

from fbchat_v2._messaging import _changeTheme, _createNotes

themes = await _changeTheme.listThemes(data_fb)
theme = await _changeTheme.findTheme(data_fb, "Love")
if theme.get("error"):
    raise RuntimeError(theme)
changed = await _changeTheme.changeTheme(
    data_fb,
    threadID="thread-id",
    themeName="Love",
)

current = await _createNotes.checkNote(data_fb)
created = await _createNotes.createNote(
    data_fb,
    text="Running async",
    privacy="FRIENDS",
)
deleted = await _createNotes.deleteNote(data_fb, noteID="note-id")
16 / MIGRATION

Chuyển từ v2.1.4 sang v2.2.0Migrating from v2.1.4 to v2.2.0

Đây là bản phát hành có thay đổi không tương thích ngược. Quá trình nâng cấp cần cập nhật call site, vòng đời listener, transport HTTP và đường import khi chuyển sang gói PyPI.This is a backward-incompatible release. The upgrade process requires updating call sites, listener lifecycle, HTTP transport, and import paths when switching to the PyPI package.

TrướcBeforeHiện tạiCurrent
data_fb = dataGetHome(cookie)
data_fb = await dataGetHome(cookie)
result = _search.func(data_fb, "Minh")
result = await _search.func(data_fb, "Minh")
result = sender.send(data_fb, "hi", uid)
result = await sender.send(data_fb, "hi", uid)
threading.Thread(target=listener.connect_mqtt)
task = asyncio.create_task(listener.connect_mqtt())
func_async(...)
func_sync(...)
await func(...)
requests.Session()
httpx.AsyncClient()

Danh sách kiểm tra nâng cấpMigration Checklist

  1. Nâng cấp package và cố định phiên bản fbchat-v2==2.2.0 trong môi trường staging.Upgrade package and pin version fbchat-v2==2.2.0 in staging environment.
  2. Cập nhật mọi lời gọi API mạng để sử dụng await.Update all network API calls to use await.
  3. Đổi import func_async/func_sync về func.Change import func_async/func_sync to func.
  4. Chỉ gọi tại điểm vào CLI duy nhất.Only call at the single CLI entry point.Chỉ gọiOnly call asyncio.run(main()) tại điểm vào CLI duy nhất.at a single CLI entry point.
  5. Tạo một httpx.AsyncClient theo lifecycle ứng dụng.Create a httpx.AsyncClient bound to app lifecycle.
  6. Chuyển listener nền từ thread target sang asyncio task được quản lý.Move background listener from thread target to managed asyncio task.
  7. Đối với E2EE, chờ trước khi gửi tin nhắn.For E2EE, wait for before sending messages.Đối với E2EE, chờFor E2EE, wait for require_e2ee=True trước khi gửi tin nhắn.before sending messages.
  8. Bổ sung quy trình dọn tài nguyên trong và kiểm thử cancellation.Add resource cleanup in and test cancellation.Bổ sung quy trình dọn tài nguyên trongAdd a resource cleanup process in finally và kiểm thử cancellation.and test cancellation.
  9. Kiểm tra dict kết quả thay vì giả định HTTP 200 luôn biểu thị thành công.Check result dict instead of assuming HTTP 200 means success.
  10. Chạy toàn bộ bộ kiểm thử và smoke test bằng cookie thử nghiệm riêng trước khi triển khai với tài khoản production.Run full test suite and smoke test with separate test cookies before deploying with production accounts.
17 / TROUBLESHOOTING

Lỗi thường gặp và hướng xử lýCommon Errors & Solutions

Xác định chính xác triệu chứng và kiểm tra tại đúng ranh giới phát sinh lỗi. Cơ chế thử lại phải có giới hạn để tránh gây checkpoint hoặc hạn chế tài khoản.Accurately identify symptoms and check at the exact boundary where the error occurs. The retry mechanism must have limits to avoid triggering a checkpoint or account restriction.

RuntimeWarning: coroutine was never awaited

Hàm async đã được gọi như hàm đồng bộ hoặc được truyền trực tiếp làm target của thread.Async function called as a synchronous function or passed directly as a thread target.

# Wrong
listener.connect_mqtt()

# Right
task = asyncio.create_task(listener.connect_mqtt())
'coroutine' object has no attribute 'get'

Kết quả coroutine chưa được await.Coroutine result not awaited.

# Wrong
info = bridge.call("connect")
user = info.get("user")

# Right
info = await bridge.call("connect")
user = info.get("user", {})
dataGetHome() trảreturns None
  1. Kiểm tra cookie có c_user, xs, fr, datr.Check if cookie has c_user, xs, fr, datr.
  2. Kiểm tra checkpoint và thời hạn phiên.Check for checkpoints and session expiration.
  3. Kiểm tra proxy và kết nối mạng tới Facebook.Check proxy and network connection to Facebook.
  4. Xác minh Facebook còn trả các token cần thiết trong HTML trang chủ.Verify Facebook still returns required tokens in homepage HTML.

Chỉ ghi tên field còn thiếu và không ghi giá trị cookie.Only log missing field names and do not log cookie values.

Upload trảUpload returns metadata: {"0": null} hoặcor 1357054

Máy chủ không trả metadata của tệp đính kèm. Bật , sau đó kiểm tra MIME, tệp, phiên đăng nhập và endpoint. Không sử dụng thay cho attachment ID.Server does not return attachment metadata. Enable , then check MIME, file, login session, and endpoint. Do not use instead of attachment ID.Máy chủ không trả metadata của tệp đính kèm. BậtServer did not return attachment metadata. Enable include_error=True, sau đó kiểm tra MIME, tệp, phiên đăng nhập và endpoint. Không sử dụng, then check MIME, file, login session and endpoint. Do not use uploadID thay cho attachment ID.

Listener E2EE không nhận lệnhE2EE Listener does not receive commands
  1. Đăng ký callback trước khi khởi động listener.Register callback before starting listener.
  2. Chờ hoàn tất.Wait for to complete.ChờWait wait_until_connected(..., require_e2ee=True) hoàn tất.to complete.
  3. Xử lý cả hai loại sự kiện e2eeMessagemessage.Handle both e2eeMessage and message.
  4. Chuyển callback về event loop bằng call_soon_threadsafe.Switch callback to event loop using call_soon_threadsafe.
  5. Kiểm tra ID của bot, prefix và cơ chế loại bỏ sự kiện trùng lặp.Check bot ID, prefix and duplicate event filtering mechanism.
  6. Kiểm tra listener task có phát sinh exception hay không.Check if the listener task raised an exception.
Bridge binary không tìm thấy hoặc sai kiến trúcBridge binary not found or wrong architecture

Xác nhận tệp phát hành phù hợp với hệ điều hành và kiến trúc, có quyền thực thi trên Unix và sử dụng đường dẫn tuyệt đối hợp lệ. Nếu tự biên dịch, cần khởi tạo bridge-e2ee/meta trước. Khi binary_path= trỏ tới tệp không tồn tại, wrapper sẽ phát sinh lỗi và không tải bản thay thế.Verify the release file matches the OS and architecture, is executable on Unix, and uses a valid absolute path. If compiling manually, initialize bridge-e2ee/meta first. When binary_path= points to a missing file, the wrapper raises an error and does not load a fallback.

Bridge liên tục khởi động lạiBridge continuously restarts

Kiểm tra stderr của bridge, trạng thái cookie, sự đồng bộ phiên bản giữa binary và mã nguồn, cùng quyền ghi tại đường dẫn lưu state. Không khởi động thêm listener để che lấp lỗi vì mỗi listener sẽ tạo thêm một tiến trình.Check bridge's stderr, cookie status, version synchronization between binary and source code, and write permission at the state storage path. Do not start extra listeners to cover up errors because each listener will spawn an additional process.

Get Notifications: slice(None, 2, None)

API notification trả về dict. Cần lấy danh sách từ NotificationResults trước khi thực hiện slice:Notification API returns a dict. You must extract the list from NotificationResults before performing slice:

result = await _notification.func(data_fb)
items = result.get("NotificationResults", [])
print(items[:2])
All Thread Data: 0 hoặc lỗi indexor index error

Không truy cập response như một list. Hãy kiểm tra , và đối tượng batch . Facebook có thể trả về đối tượng lỗi thay vì danh sách hội thoại.Do not access response as a list. Check , , and the batch object . Facebook may return an error object instead of a thread list.Không truy cập response như một list. Hãy kiểm traDo not access response as a list. Check result.get("error"), dataGet và đối tượng batchand batch object o0. Facebook có thể trả về đối tượng lỗi thay vì danh sách hội thoại.. Facebook may return an error object instead of a thread list.

Đăng nhập bằng thông tin xác thực trả mãLogging in with credentials returns code -1

Nguyên nhân thường là transport hoặc schema không khớp, hoặc phản hồi không có mã lỗi chuẩn. Hãy đọc mô tả đã được lọc, kiểm tra biến môi trường override nếu có và ưu tiên khởi tạo bằng cookie phiên. Chỉ kết luận mật khẩu không hợp lệ khi phản hồi cung cấp đầy đủ bằng chứng.Usually caused by transport/schema mismatch, or response lacks standard error code. Read the filtered description, check override env vars if any, and prioritize session cookie initialization. Only conclude invalid password when the response provides sufficient evidence.

18 / SECURITY

Bảo mật và giới hạnSecurity & Limits

Thư viện thao tác trên tài khoản Facebook thật thông qua các endpoint nội bộ. Quyền của bot gần tương đương quyền của phiên cookie, do đó phạm vi ảnh hưởng khi thông tin phiên bị lộ là đáng kể.The library operates on a real Facebook account through internal endpoints. The bot's privileges are almost equivalent to the cookie session's privileges, therefore the impact is significant if session information is leaked.

01

Quản lý thông tin bí mậtManage Secrets

Lưu cookie trong secret manager hoặc tệp cục bộ bị Git bỏ qua. Làm mới phiên ngay khi có dấu hiệu bị lộ.Store cookies in a secret manager or local files ignored by Git. Refresh the session immediately upon signs of exposure.

02

Đặc quyền tối thiểuLeast Privilege

Sử dụng tài khoản riêng cho tự động hóa, giới hạn lệnh quản trị và áp dụng danh sách cho phép đối với người gửi hoặc hội thoại.Use a separate account for automation, limit administrative commands, and apply a whitelist for senders or conversations.

03

Nhật ký an toànSafe Logging

Chỉ ghi loại sự kiện, message ID rút gọn và lớp lỗi. Không ghi nội dung request, cookie, token, mật khẩu hoặc TOTP.Log only the event type, truncated message ID, and error class. Do not log request contents, cookies, tokens, passwords, or TOTP.

04

Xác minh TLSTLS Verification

Luôn giữ xác minh chứng chỉ. Không sử dụng verify=False hoặc CERT_NONE để xử lý lỗi proxy.Always keep certificate verification. Do not use verify=False or CERT_NONE to handle proxy errors.

05

Kiểm soát tần suấtRate Limiting

Sử dụng timeout, hàng đợi có giới hạn, backoff hữu hạn và cơ chế idempotency tại tầng ứng dụng.Use timeouts, bounded queues, finite backoff, and application-level idempotency.

06

Độ tin cậy của phụ thuộcDependency Reliability

Cố định phiên bản, kiểm tra tệp phát hành và cập nhật đồng bộ bridge với Python wrapper.Pin versions, verify release files, and keep the bridge synchronized with the Python wrapper.

Không ghi dataFB vào nhật kýDo Not Log dataFB

def safe_session_status(data_fb: dict) -> dict:
    required = (
        "FacebookID",
        "fb_dtsg",
        "jazoest",
        "sessionID",
        "clientRevision",
        "cookieFacebook",
    )
    return {
        "facebook_id_present": bool(data_fb.get("FacebookID")),
        "missing_fields": [key for key in required if not data_fb.get(key)],
    }
TUYÊN BỐ MIỄN TRỪDISCLAIMER

fbchat-v2 không phải SDK chính thức của Meta. Endpoint, HTML, token, subcode và chính sách có thể thay đổi bất kỳ lúc nào. Việc sử dụng có thể dẫn tới checkpoint hoặc hạn chế tài khoản. Người triển khai chịu trách nhiệm bảo vệ tài khoản và đánh giá rủi ro sử dụng.fbchat-v2 is not an official Meta SDK. Endpoints, HTML, tokens, subcodes, and policies can change at any time. Usage may lead to checkpoints or account restrictions. Implementers are responsible for securing accounts and assessing usage risks.

19 / QUALITY GATES

Kiểm thử và phát hànhTesting & Release

Thực hiện đầy đủ các bước kiểm tra Python, bridge Go, encoding và diff trước khi push. Tệp phát hành E2EE phải được biên dịch và tải lên riêng; GitHub chỉ tự động tạo gói mã nguồn ZIP và TAR.Perform full Python, Go bridge, encoding, and diff checks before pushing. E2EE release files must be compiled and uploaded separately; GitHub only automatically creates ZIP and TAR source packages.

pytest tests/ -v --tb=short
python -m compileall -q src tests
ruff check src tests
ruff format --check src tests
git diff --check

Danh sách kiểm tra phát hànhRelease Checklist

  • Phiên bản trong package, tag, changelog và ghi chú phát hành phải khớp nhau.Versions in package, tag, changelog, and release notes must match.
  • Bộ kiểm thử được chạy trên Python 3.10, 3.11, 3.12 hoặc ma trận phiên bản mà dự án công bố hỗ trợ.The test suite runs on Python 3.10, 3.11, 3.12, or the version matrix officially supported by the project.
  • Bridge được biên dịch đầy đủ cho Windows, Linux và macOS với kiến trúc amd64 hoặc arm64 tương ứng.Bridge is fully compiled for Windows, Linux, and macOS with respective amd64 or arm64 architectures.
  • Không đưa thông tin bí mật, cấu hình cục bộ, cơ sở dữ liệu, báo cáo nội bộ hoặc binary ngoài phạm vi vào staging area.Do not include secrets, local configs, databases, internal reports, or out-of-scope binaries in the staging area.
  • Kiểm tra UTF-8 không hợp lệ, U+FFFD, NUL và dấu hiệu mojibake thực tế trước khi commit.Check for invalid UTF-8, U+FFFD, NUL, and actual mojibake signs before committing.
  • Commit dùng conventional format có scope, ví dụ docs(website): expand async v2.2 documentation.Commit using conventional format with scope, e.g. docs(website): expand async v2.2 documentation.

Cộng đồng & Ghi công Community & Credits

MinhHuyDev
MinhHuyDev
OWNER & MAINTAINER
Hakiraxx
Hakiraxx
SUPER-CONTRIBUTOR
T
tomdev112
@TOMDEV211
S
syrex1013
@SYREX1013
K
Kheir Eddine
FACEBOOK
向世玉
COMMUNITY
J
Jihadi John
COMMUNITY
B
Bắc Trịnh
FACEBOOK
Q
Quang Trần
FACEBOOK
M
Minh Trần Ngọc
FACEBOOK
V
Victor Knutsenberger
COMMUNITY
H
Hoàng Lân
FACEBOOK
K
Kareem Adel Abomandor
COMMUNITY
L
@lluevy
GITHUB
P
@phuncnheo
GITHUB
M
@minhphatnw
GITHUB
K
@khanh235a
GITHUB
C
@chapesh1
GITHUB
K
@klongg13
GITHUB
S
@seafibrahem
GITHUB
A
@agent1047
GITHUB
S
@stefekdziura
GITHUB

Quy tắc Ứng xử Code of Conduct

Vui lòng tuân thủ quy tắc ứng xử của cộng đồng khi tham gia đóng góp. Please follow the community code of conduct when participating.

Chúng tôi cam kết tạo ra một môi trường thân thiện, an toàn và hòa nhập cho tất cả mọi người. Mọi hành vi quấy rối hoặc không tôn trọng sẽ không được dung thứ. Mọi thành viên đóng góp đều phải sử dụng ngôn từ lịch sự và tôn trọng. We are committed to providing a friendly, safe and welcoming environment for all. Harassment or disrespect of any kind will not be tolerated. All contributors must use polite and respectful language.