Skip to main content

A modern, strictly-typed Python wrapper for the Meta Messenger Platform (Graph API).

Most Python libraries for Facebook Messenger are either abandoned, lack type hints, or were written back in the Python 2/3 transition era. pymsgr was built to give developers an intuitive, production-grade experience using modern Python (3.10+), Pydantic v2, and full typing support.

Note & Credit: This project is heavily inspired by pywa (the awesome WhatsApp Cloud API library). If you've used pywa before, you'll feel right at home with the handler syntax, contextual replies, and overall developer experience.


Features

  • Strictly Typed & Autocomplete-Ready: Built from the ground up with Pydantic v2. Your IDE knows every incoming event field and outbound payload parameter.
  • Contextual Reply Helpers: Reply directly using msg.reply_text(), msg.reply_buttons(), or msg.typing_on() without juggling PSIDs and page IDs manually.
  • Built-in Webhook Handlers: Zero-boilerplate webhook setup with first-class support for both FastAPI and Flask.
  • Webhook Security Out of the Box: Automatic HMAC-SHA256 signature verification (X-Hub-Signature-256) and verification challenge (hub.challenge) handshakes.
  • Multi-Tenant / SaaS Friendly: Pass a single token, a mapping dictionary, or a dynamic callable/database lookup function for multi-page bots.
  • Rich Templates: Clean models for Buttons, Generic Templates (Carousels), Quick Replies, and sender actions.

Installation

Install with pip:

pip install pymsgr

Or install with webhook integrations:

# For FastAPI & Uvicorn
pip install "pymsgr[fastapi]"

# For Flask
pip install "pymsgr[flask]"

# Everything included
pip install "pymsgr[all]"

Quick Start (FastAPI)

Here is a simple bot that verifies your webhook and echoes back greetings:

from fastapi import FastAPI
import uvicorn

from pymsgr import Messenger
from pymsgr.server import FastAPIIntegration
from pymsgr.types import Message, QuickReply

app = FastAPI()

bot = Messenger(
    page_access_token="YOUR_PAGE_ACCESS_TOKEN",
    verify_token="YOUR_CUSTOM_VERIFY_TOKEN",
    app_secret="YOUR_META_APP_SECRET",
)

# Automatically registers GET and POST routes on /webhook
FastAPIIntegration(bot, app, path="/webhook")


@bot.on_message()
def handle_message(msg: Message):
    # Contextual shortcuts — no need to pass sender_id or page_id
    if msg.text and msg.text.lower() == "hello":
        msg.reply_text(
            text="Hey there! How can I help you today?",
            quick_replies=[
                QuickReply(title="Pricing", payload="ACTION_PRICING"),
                QuickReply(title="Contact Support", payload="ACTION_SUPPORT"),
            ],
        )


@bot.on_postback()
def handle_postback(msg: Message):
    if msg.postback_payload == "GET_STARTED":
        msg.reply_text("Welcome aboard! Let's get started.")


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Using with Flask

Prefer Flask? The setup is just as simple:

from flask import Flask
from pymsgr import Messenger
from pymsgr.server import FlaskIntegration
from pymsgr.types import Message

app = Flask(__name__)

bot = Messenger(
    page_access_token="YOUR_PAGE_ACCESS_TOKEN",
    verify_token="YOUR_CUSTOM_VERIFY_TOKEN",
    app_secret="YOUR_META_APP_SECRET",
)

FlaskIntegration(bot, app, path="/webhook")


@bot.on_message()
def handle_message(msg: Message):
    msg.reply_text(f"You said: {msg.text}")


if __name__ == "__main__":
    app.run(port=8000)

Multi-Page & SaaS Architecture

If you're building a multi-tenant bot where different Facebook Pages use the same backend, you don't need multiple client instances. pymsgr allows dynamic token resolution:

1. Dictionary Mapping

bot = Messenger(
    page_access_token={
        "PAGE_ID_1": "TOKEN_FOR_PAGE_1",
        "PAGE_ID_2": "TOKEN_FOR_PAGE_2",
    },
    verify_token="shared_verify_token",
    app_secret="shared_app_secret",
)

2. Dynamic Database Lookup (Callable)

def get_page_token(page_id: str) -> str:
    # Fetch token from your database or cache
    page = db.query(Page).filter_by(id=page_id).first()
    return page.access_token


bot = Messenger(
    page_access_token=get_page_token,
    verify_token="shared_verify_token",
    app_secret="shared_app_secret",
)

Interactive Message Templates

Button Template

from pymsgr.types import PostbackButton, UrlButton

bot.send_buttons(
    psid=user_id,
    page_id=page_id,
    text="What would you like to check out?",
    buttons=[
        UrlButton(title="Visit Website", url="https://example.com"),
        PostbackButton(title="View Order", payload="VIEW_ORDER_123"),
    ],
)
from pymsgr.types import GenericElement, PostbackButton, UrlButton

elements = [
    GenericElement(
        title="Product 1",
        subtitle="$29.99 - In Stock",
        image_url="https://example.com/item1.jpg",
        buttons=[PostbackButton(title="Buy Now", payload="BUY_1")],
    ),
    GenericElement(
        title="Product 2",
        subtitle="$49.99 - Limited Supply",
        image_url="https://example.com/item2.jpg",
        buttons=[PostbackButton(title="Buy Now", payload="BUY_2")],
    ),
]

bot.send_generic_template(psid=user_id, page_id=page_id, elements=elements)

Event Handlers

You can register listeners for various incoming events:

@bot.on_message()
def on_msg(msg: Message): ...

@bot.on_postback()
def on_postback(msg: Message): ...

@bot.on_read()
def on_read(msg: Message): ...

@bot.on_delivery()
def on_delivery(msg: Message): ...

@bot.on_reaction()
def on_reaction(msg: Message): ...

Contributing

Contributions are always welcome! Feel free to open an issue if you discover a bug or want to request a feature, or submit a pull request directly.

  1. Fork the repository
  2. Create your branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

Metadata

Release files for pymsgr 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pymsgr 0.1.0
File Size Uploaded
pymsgr-0.1.0.tar.gz 27.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pymsgr 0.1.0
File Interpreter ABI Platform
pymsgr-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 52.2 kB

Release files / pymsgr-0.1.0.tar.gz

Download URL pymsgr-0.1.0.tar.gz
Size 27.6 kB
Tags Source
SHA-256 checksum
How to use checksums
d3cc06c019029e6660c03a15af90abe8300f8ee9094fc12980c4de7b9bf85996
BLAKE2b-256 checksum
How to use checksums
44ef97660ffc006cbeca474c5d78e9deae48d508c452cfad55a76fc48ae1338c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / pymsgr-0.1.0-py3-none-any.whl

Download URL pymsgr-0.1.0-py3-none-any.whl
Size 24.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bd29a0d19ee8134d050815b82f16dd57c58e5347eafa67c3bdc9bf924efa696b
BLAKE2b-256 checksum
How to use checksums
d117befa09d0bed9186d9f25b2877555c710e102e628d10d8fdeb0bbb57a9ca7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page