PHPackages                             torgodly/messenger-bot - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. torgodly/messenger-bot

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

torgodly/messenger-bot
======================

Facebook Messenger webhooks and Page comments for Laravel (BotMan-style API, no BotMan dependency).

2.2.0(2w ago)014↓100%MITPHPPHP ^8.3

Since May 4Pushed 2w agoCompare

[ Source](https://github.com/torgodly/messenger-bot)[ Packagist](https://packagist.org/packages/torgodly/messenger-bot)[ Docs](https://packagist.org/packages/torgodly/messenger-bot)[ RSS](/packages/torgodly-messenger-bot/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (14)Versions (7)Used By (0)

torgodly/messenger-bot
======================

[](#torgodlymessenger-bot)

Facebook Messenger webhooks for Laravel (messages, postbacks, quick replies, feed comments). BotMan-style API (`hears`, `payload`, `onComment`) without BotMan.

**PHP 8.3+ · Laravel 12 or 13 · Composer `^2.2`**

---

Quick start
-----------

[](#quick-start)

### Single Facebook Page (default)

[](#single-facebook-page-default)

```
composer require torgodly/messenger-bot:^2.2
php artisan vendor:publish --tag=messenger-bot-config
php artisan messenger-bot:install
```

Register handlers in `AppServiceProvider::boot()`. No tenant config.

### Multi-tenant (many Pages)

[](#multi-tenant-many-pages)

```
php artisan messenger-bot:install --tenant --model=App\Models\YourFacebookPage
```

Set in `.env` (no quotes around the FQCN):

```
MESSENGER_BOT_TENANCY_ENABLED=true
MESSENGER_BOT_TENANCY_CONNECTION_MODEL=App\Models\YourFacebookPage
MESSENGER_BOT_TENANCY_PAGE_ID_COLUMN=page_id
MESSENGER_BOT_AUTO_SUBSCRIBE_AFTER_OAUTH=true
MESSENGER_BOT_AUTO_SYNC_MENU_AFTER_OAUTH=true
MESSENGER_BOT_OAUTH_PENDING_PAGES_URL=https://YOUR-DOMAIN/meta/pick-page
MESSENGER_BOT_VALIDATES_PAGE_LINK=App\\Messenger\\YourPageLinkValidator
```

Your model must extend Eloquent `Model` and implement `MessengerBot\Contracts\MessengerConnectable` (trait `InteractsWithMessengerConnection` is recommended). Wrong model class **fails fast in `local` / `testing`**.

**Business rules (enforced by your app via `ValidatesMessengerPageLink`):**

- One Graph Page ID → at most one tenant at a time.
- One tenant → at most one linked Page at a time (reconnecting the **same** `page_id` is allowed).

---

Meta Developer checklist
------------------------

[](#meta-developer-checklist)

StepWhat to doAppMessenger product + Facebook Login; add your Page.OAuth redirectExact match: `https://YOUR-DOMAIN/messenger-bot/oauth/facebook/callback` (or `MESSENGER_BOT_OAUTH_REDIRECT_URI`). Production needs **HTTPS**; `APP_URL` must match.WebhookCallback `https://YOUR-DOMAIN/webhook/messenger`, verify token = `MESSENGER_BOT_VERIFY_TOKEN`.FieldsEnable fields in config `webhook_fields` — include **`feed`** for Page comments. `messenger-bot:install` / `sync-page` can subscribe via Graph.TokensProduction: `MESSENGER_BOT_PAGE_TOKEN_CACHE_STORE` and/or `MESSENGER_BOT_CONNECTION_TOKEN_CACHE_STORE` = `redis` or `database`.Routes register **outside** the `web` middleware group (avoids CSRF **419** on Meta POSTs).

---

Handlers
--------

[](#handlers)

```
use MessengerBot\Facades\MessengerBot;

MessengerBot::hears('hi', fn ($bot, $message) => $bot->reply('Hello!'));
MessengerBot::payload('GET_STARTED', fn ($bot, $postback) => $bot->reply('Welcome!'));

MessengerBot::onComment(function ($bot, $comment) {
    $bot->replyToComment($comment->id, 'Thanks!');
});

MessengerBot::fallback(fn ($bot, $message) => $bot->reply('Use the menu.'));
```

- **Priority:** `MessengerBot::hears('pattern', $handler, priority: 10)`
- **Get Started:** `payload()` for `MESSENGER_BOT_GET_STARTED_PAYLOAD` or `MESSENGER_BOT_GET_STARTED_REPLY`
- **Comments:** `CommentCreated` is dispatched before `onComment` handlers (see Events)

Optional host config `comment_handlers.queue` — infrastructure only; the package does **not** ship DB comment rules. See [README-EXTERNAL-RULES.md](README-EXTERNAL-RULES.md).

---

Multi-tenant
------------

[](#multi-tenant)

Config / envPurpose`tenancy.connection_model` / `MESSENGER_BOT_TENANCY_CONNECTION_MODEL`Eloquent class implementing `MessengerConnectable``tenancy.connection_page_id_column` / `MESSENGER_BOT_TENANCY_PAGE_ID_COLUMN`Column matched to Meta Page ID (default `facebook_page_id`; many apps use `page_id`)Model `messengerFacebookPageIdColumn()`Override column name on the model**OAuth redirect:**

```
use MessengerBot\Facades\MessengerOAuth;

return MessengerOAuth::redirectToFacebook($pageModel);
```

### Multi-Page OAuth flow (no package UI)

[](#multi-page-oauth-flow-no-package-ui)

Facebook may return **0, 1, or many** managed Pages.

CountBehaviour0Error 4001`CompleteOAuthPageLink` stores token → redirect success2+**Not an error.** No token stored. All Pages cached → redirect `MESSENGER_BOT_OAUTH_PENDING_PAGES_URL?token=`Your app shows a Page picker (Filament, Livewire, etc.). After the user chooses:

```
use MessengerBot\OAuth\CompleteOAuthPageLink;
use MessengerBot\OAuth\PendingOAuthPages;

$payload = PendingOAuthPages::pull($request->query('token'));
// $payload['pages'], $payload['mt']

app(CompleteOAuthPageLink::class)->complete($chosenPage, $payload['mt']);
```

**`ValidatesMessengerPageLink`** — implement in your app:

```
use MessengerBot\Contracts\ValidatesMessengerPageLink;

final class YourPageLinkValidator implements ValidatesMessengerPageLink
{
    public function assertMayLinkPage(array $page, array $mt): void
    {
        // Block if page_id belongs to another tenant
        // Block if tenant already has a different page_id
        // Allow reconnect when page_id unchanged
    }
}
```

On rejection, OAuth redirect uses session flash key **`messenger_bot_oauth_error`**.

Optional: `MESSENGER_BOT_OAUTH_PREFERRED_PAGE_ID` — when exactly one Page in the list matches, link immediately (skip pending redirect).

EnvPurpose`MESSENGER_BOT_OAUTH_PENDING_PAGES_URL`Required when tenancy enabled`MESSENGER_BOT_OAUTH_PENDING_PAGES_TTL`Cache minutes (default `10`)`MESSENGER_BOT_OAUTH_PENDING_PAGES_CACHE_PREFIX`Default `messenger_bot:oauth_pages:``MESSENGER_BOT_VALIDATES_PAGE_LINK`FQCN for validator (required when tenancy enabled)**Webhook context:**

```
app(\MessengerBot\Laravel\MessengerCurrentConnection::class)->resolution();
```

**Resolver behaviour:** looks up the model by Page ID column; if missing, falls back to the **connection token page index** and fires `ConnectablePageIdSynced` so your app can persist `page_id` on the row.

**Advanced:** `MESSENGER_BOT_TENANCY_RESOLVER` for a custom `TenantResolver`; optional `EloquentMessengerTenantResolver` subclass (see `stubs/eloquent_messenger_tenant_resolver.php.stub`).

---

After OAuth automation
----------------------

[](#after-oauth-automation)

When multi-tenant OAuth stores a token, `ConnectionTokenStored` runs. Enable automatic webhook subscribe + persistent menu sync:

```
MESSENGER_BOT_AUTO_SUBSCRIBE_AFTER_OAUTH=true
MESSENGER_BOT_AUTO_SYNC_MENU_AFTER_OAUTH=true
MESSENGER_BOT_LINK_SKIP_TOKEN_CHECK=false
MESSENGER_BOT_AFTER_OAUTH_QUEUE=false
```

Config block: `messenger-bot.after_connection_token_stored`. Replaces most host wrappers around `ConnectionTokenRepository::put()`.

On failure, the package logs and may queue `SyncPageProfileAfterOAuthJob` when `queue_retry_on_failure` is true.

---

Events
------

[](#events)

EventWhen`WebhookReceived`Raw webhook payload`MessageReceived`Incoming message`PostbackReceived`Postback`CommentCreated`Top-level feed comment`ConnectionTokenStored`After `ConnectionTokenRepository::put()``ConnectablePageIdSynced`Tenant resolved from token index (DB `page_id` empty)`PostsSynced`, `PostsCacheHit`, `PostsCacheMiss`Posts syncOutgoing `OutgoingMessage*`Send pipeline---

DB-driven rules (your app)
--------------------------

[](#db-driven-rules-your-app)

The package does not store tenant rules. Load rules from **your** database inside handlers or a small engine — no `optimize:clear` needed.

**Guide:** [README-EXTERNAL-RULES.md](README-EXTERNAL-RULES.md)

### Reference implementation: Matager

[](#reference-implementation-matager)

Matager (not included in this package) shows a production pattern:

- `CommentRuleEngine` — reads `MetaCommentRule` rows per tenant
- `MetaCommentPostId` — normalizes Graph post IDs for `onlyForPostIds`
- `MessengerBot::onComment` → engine or queued `ProcessMetaCommentRuleJob`
- `PersistFacebookPageAfterOAuthListener` on `ConnectionTokenStored` — saves `page_id` on `FacebookPage`
- Filament admin for rules — stays in the host app

Use Matager as a reference; copy patterns, not the package.

---

Page posts, Artisan, troubleshooting
------------------------------------

[](#page-posts-artisan-troubleshooting)

**Posts:** `SyncsFacebookPagePosts`, `PostsSyncRequest::forConnectable()`, `RefreshPostsCacheJob::forConnectable()` — see previous examples in [CHANGELOG](CHANGELOG.md) / v2.0 notes.

**Artisan:** `messenger-bot:install`, `install --tenant --model=`, `sync-page`, `token-status`, `clear-page-token`.

**Troubleshooting**

SymptomCheckComments ignored / `tenant_unresolved``feed` subscribed; `MESSENGER_BOT_TENANCY_CONNECTION_MODEL` + `MESSENGER_BOT_TENANCY_PAGE_ID_COLUMN`; Page linked via OAuth; token cache has page indexWebhook 403`MESSENGER_BOT_APP_SECRET` matches MetaOAuth / webhook 419Routes must not use `web` CSRF; package registers outside `web` by defaultInvalid tenancy modelException in `local`/`testing`; production logs critical and disables configurable resolver---

Upgrade `2.1` → `2.2`
---------------------

[](#upgrade-21--22)

1. `composer require torgodly/messenger-bot:^2.2`
2. Set `MESSENGER_BOT_OAUTH_PENDING_PAGES_URL` and `MESSENGER_BOT_VALIDATES_PAGE_LINK` when tenancy is on
3. Implement `ValidatesMessengerPageLink` for Page/tenant uniqueness
4. Build a Page picker route that reads `?token=`, calls `PendingOAuthPages::pull()`, then `CompleteOAuthPageLink::complete()`
5. **Breaking:** multiple Pages from OAuth are **no longer** auto-linked to the first Page

Upgrade `2.0` → `2.1`
---------------------

[](#upgrade-20--21)

1. `composer require torgodly/messenger-bot:^2.1`
2. Publish / merge config for `after_connection_token_stored` and `comment_handlers`
3. Replace host `put()` wrappers with `MESSENGER_BOT_AUTO_SUBSCRIBE_AFTER_OAUTH` / `MESSENGER_BOT_AUTO_SYNC_MENU_AFTER_OAUTH`
4. Listen to `ConnectionTokenStored` for DB hydration (`page_id`) instead of wrapping the repository
5. Remove custom resolvers that only duplicated token page-index lookup — use package fallback + `ConnectablePageIdSynced`

---

References
----------

[](#references)

- [Messenger templates](https://developers.facebook.com/docs/messenger-platform/send-messages/templates)
- [README-EXTERNAL-RULES.md](README-EXTERNAL-RULES.md)
- [CHANGELOG.md](CHANGELOG.md)

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance96

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

6

Last Release

19d ago

Major Versions

v1.1.1 → v2.0.02026-05-07

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/57685643?v=4)[Abdullah al-hajj](/maintainers/torgodly)[@torgodly](https://github.com/torgodly)

---

Top Contributors

[![torgodly](https://avatars.githubusercontent.com/u/57685643?v=4)](https://github.com/torgodly "torgodly (10 commits)")

---

Tags

laravelfacebookoauthwebhookMessengerchatbotgraph-apifacebook messenger

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/torgodly-messenger-bot/health.svg)

```
[![Health](https://phpackages.com/badges/torgodly-messenger-bot/health.svg)](https://phpackages.com/packages/torgodly-messenger-bot)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k14.1M120](/packages/laravel-pulse)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9732.3M121](/packages/roots-acorn)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k51.0M7.4k](/packages/larastan-larastan)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

76318.2M110](/packages/laravel-mcp)[flarum/core

Delightfully simple forum software.

261.4M2.2k](/packages/flarum-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
