Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Fb Messenger Laravel Package

casperlaitw/laravel-fb-messenger

Laravel wrapper for the Facebook Messenger Platform that simplifies building bots: handle webhooks, send text and rich messages, manage persistent menus, and integrate Messenger features into your Laravel app with a clean, expressive API.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal steps to a working bot:

  1. Install

    composer require casperlaitw/laravel-fb-messenger
    

    On Laravel ≥5.5 package auto-discovery registers CasperLaitw\LaravelFbMessenger\LaravelFbMessengerServiceProvider and the FacebookMessenger facade. On older versions add both manually in config/app.php.

  2. Publish config

    php artisan vendor:publish --provider="CasperLaitw\LaravelFbMessenger\LaravelFbMessengerServiceProvider"
    

    This drops config/laravel-fb-messenger.php.

  3. Fill .env — this is where most first-run failures happen:

    FB_MESSENGER_APP_TOKEN=      # App Secret from the Facebook app dashboard
    FB_MESSENGER_PAGE_TOKEN=     # Page Access Token (long-lived, not user token)
    FB_MESSENGER_WEBHOOK_TOKEN=  # Arbitrary string you also paste into the FB dashboard
    FB_MESSENGER_API_VERSION=v18.0
    

    The config ships with an old default API version (2.x-era). Bump it; most endpoints still work but the SDK's defaults are stale.

  4. Create a handler. The package's idiomatic entry point is a class that receives parsed events (message, postback, authentication). Extend the package's base Handler (or implement its handler interface — check src/ in your installed version for the exact method names, since this is a thin, small package and the contract has shifted across releases):

    use CasperLaitw\LaravelFbMessenger\Handler;
    
    class EchoBot extends Handler
    {
        public function handleMessage($message)
        {
            $this->sender->sendText($message->getSenderId(), 'You said: '.$message->getText());
        }
    
        public function handlePostback($postback) { /* menu clicks */ }
        public function handleAuthentication($auth) { /* account linking */ }
    }
    
  5. Expose the webhook. Two routes, and they are not interchangeable:

    Route::get('/webhook',  'WebhookController@verify');   // FB subscription handshake
    Route::post('/webhook', 'WebhookController@handle');   // event delivery
    
    public function verify(Request $request)
    {
        if ($request->input('hub_verify_token') === config('laravel-fb-messenger.webhook_token')) {
            return response($request->input('hub_challenge'), 200)
                ->header('Content-Type', 'text/plain');
        }
        abort(403);
    }
    
    public function handle(Request $request)
    {
        FacebookMessenger::handle($request->all()); // dispatch into your handler
        return response('OK', 200);
    }
    
  6. Where to look first: config/laravel-fb-messenger.php for tokens/version, then the package's src/Handler.php / src/Contracts/ for the exact dispatch signatures, then the underlying pimax/fb-messenger-php vendor source for message-building helpers. Don't trust blog posts — the API surface is small enough to read in ten minutes.

First use case: an echo bot that replies to text messages, then a postback handler that fires from a "Get Started" button. That covers 90% of what this package is used for in practice.

Implementation Patterns

Event dispatch into a handler. Rather than parsing entry[].messaging[] yourself, keep all routing inside your handler class: one method per event type. This is the package's main value-add over raw cURL — it normalizes the webhook envelope into typed objects (MessageReceived, PostbackReceived, AuthenticationReceived, etc.).

Sending rich content. Go through the facade (or the sender you get inside the handler). The underlying SDK exposes text, quick replies, buttons, generic (card carousel) templates, attachments, and sender actions ("typing_on"). Compose these inline:

$this->sender->sendButtonTemplate($userId, 'Pick one', [
    ['type' => 'postback', 'title' => 'Yes', 'payload' => 'CONFIRM_YES'],
    ['type' => 'postback', 'title' => 'No',  'payload' => 'CONFIRM_NO'],
]);

Webhook controller should do nothing but route. Keep handle() to: parse, dispatch to a queued job, return 200. Facebook gives you a short window before it retries; slow handlers cause duplicate deliveries.

public function handle(Request $request)
{
    Log::channel('fb')->info('webhook', $request->all()); // keep raw payloads
    ProcessMessengerEvent::dispatch($request->all());
    return response('OK', 200);
}

Queue the work. The job runs the handler, does profile lookups, calls out to your domain logic, and sends replies. This also lets you retry transient send failures (rate limits, 500s from Graph API) without FB redelivering the event.

One-time Messenger Profile setup. Persistent menu, greeting text, "Get Started" button, and whitelisted domains are configuration, not per-message calls. Wrap them in an artisan command (php artisan fb:setup-profile) so they're reproducible across environments instead of being run once by hand in Graph API Explorer.

Testing. Fake the facade in feature tests (FacebookMessenger::shouldReceive('sendText')...) and post fixture payloads at your webhook route. Keep a small set of captured real webhook JSON bodies in tests/fixtures/ — message, postback, and delivery/read receipts at minimum — and assert your handler responds correctly. For the handshake, assert the challenge is echoed byte-for-byte.

Signature verification middleware. Add a middleware that computes hash_hmac('sha1', $rawBody, config('...app_token')) and compares against X-Hub-Signature. The package does not reliably do this for you; verifying it is your job and it's the difference between a bot and an open endpoint.

Gotchas and Tips

  • CSRF will break the POST webhook. Add the path to $except in app/Http/Middleware/VerifyCsrfToken.php. This is the single most common "my bot works locally but not in production" bug.
  • Return the challenge as plain text, not JSON. response($challenge)->header('Content-Type','text/plain'). Laravel's default JSON response for strings will fail verification in the FB dashboard.
  • App token vs page token. Sends require the page token; some profile/verification calls need the app secret. Mixing them up produces (#190) Invalid OAuth access token with no further detail.
  • The API version in the published config is ancient. Set FB_MESSENGER_API_VERSION to a current version. Newer Facebook features (handover protocol, icebreakers, some template fields) simply aren't in the bundled SDK — you'll be writing raw requests via Http:: for those.
  • Webhook retries cause duplicates. FB retries when you return non-200 or time out. Store the message mid and dedupe in the job; it's cheaper than apologizing for double replies.
  • Response body matters less than status code. Return 200 quickly, even if processing is queued. A 500 triggers immediate retry storms.
  • 24-hour messaging window. Bots can only message users within 24h of their last interaction (unless using message tags). This is platform policy, not a package limitation — but the package won't warn you, you'll just get error 10 / 2018278.
  • Payload size limits. Postback payloads are capped at 640 bytes; text messages at 2000 chars. Truncate defensively or you'll get opaque 400s.
  • Package maintenance is a real risk. Last release was Aug 2021; it depends on an older pimax/fb-messenger-php. On Laravel 10/11 you may hit dependency conflicts or missing typed signatures. Before committing, verify it installs cleanly and budget time for a fork — the package is small (src/ is a few files), so vendoring or reimplementing the wrapper around the SDK is often cheaper than fighting compatibility.
  • Debugging tip: log the raw $request->all() before dispatch. Handler-level failures hide the envelope, and Facebook's webhook log in the app dashboard only shows delivery attempts, not your internal errors.
  • HTTPS and a public URL. Local ngrok/Expose works, but update the webhook URL in the FB dashboard each time the tunnel host changes — and re-verify, since the handshake is per-URL.
  • Extension point: anything the SDK can't express, drop to Illuminate\Support\Facades\Http with the page token and version from config. Don't fight the wrapper — the package is a convenience around the Graph API, not an abstraction you should protect.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core