PHPackages                             igedeon/laravel-whatsapp - 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. [API Development](/categories/api)
4. /
5. igedeon/laravel-whatsapp

ActiveLibrary[API Development](/categories/api)

igedeon/laravel-whatsapp
========================

Librería Laravel para enviar y recibir mensajes WhatsApp Cloud API (multi-número)

v1.6.9(1mo ago)2418MITPHPPHP ^8.2CI passing

Since Oct 30Pushed 1mo agoCompare

[ Source](https://github.com/IGedeon/laravel-whatsapp)[ Packagist](https://packagist.org/packages/igedeon/laravel-whatsapp)[ RSS](/packages/igedeon-laravel-whatsapp/feed)WikiDiscussions master Synced yesterday

READMEChangelog (10)Dependencies (40)Versions (37)Used By (0)

[![Tests](https://github.com/IGedeon/laravel-whatsapp/actions/workflows/test.yml/badge.svg)](https://github.com/IGedeon/laravel-whatsapp/actions/workflows/test.yml)[![Lint](https://github.com/IGedeon/laravel-whatsapp/actions/workflows/lint.yml/badge.svg)](https://github.com/IGedeon/laravel-whatsapp/actions/workflows/lint.yml)[![Latest Version](https://camo.githubusercontent.com/cf49997fb47ed01e26e48ac02e831f0d0d9b506e3d60bb66c30aa5128441e145/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f69676564656f6e2f6c61726176656c2d7768617473617070)](https://packagist.org/packages/igedeon/laravel-whatsapp)[![Total Downloads](https://camo.githubusercontent.com/24405f930ad62b4aae21d3507d7c35400dcd1522f307fb14b680b1f456510e17/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f69676564656f6e2f6c61726176656c2d7768617473617070)](https://packagist.org/packages/igedeon/laravel-whatsapp)[![PHP Version](https://camo.githubusercontent.com/8eefc9897f0b9f71adb87d464a532f14350c67e770817d940e75059d8d815bc6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f69676564656f6e2f6c61726176656c2d77686174736170702f706870)](https://packagist.org/packages/igedeon/laravel-whatsapp)[![License](https://camo.githubusercontent.com/a1e59446aa3967e11e8465336051d5644ca206a4aa7726e7920f8e99bee08c07/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f69676564656f6e2f6c61726176656c2d7768617473617070)](https://packagist.org/packages/igedeon/laravel-whatsapp)

Laravel WhatsApp Cloud API
==========================

[](#laravel-whatsapp-cloud-api)

[Versión en Español](./README.es.md)

Laravel package to integrate Meta's WhatsApp Cloud API with support for multiple Meta Apps, Business Accounts (WABAs), Access Tokens, and Phone Numbers.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 12 or 13

Features
--------

[](#features)

- Multiple Meta Apps, WABAs, Access Tokens, and Phone Numbers
- Centralized webhook with multi-secret HMAC-SHA256 signature verification
- Full persistence: contacts, messages, templates, media, tokens, errors
- Business-Scoped User ID (BSUID) support — handles users who enable the WhatsApp username feature
- Media upload &amp; download (images, documents, audio, video, stickers)
- Optional queues for media download and mark-as-read
- Template message support (Meta-approved templates)
- Interactive `whatsapp:configure` command for guided setup
- [Laravel Boost](https://laravel.com/docs/boost) AI guidelines included

---

Installation
------------

[](#installation)

```
composer require igedeon/laravel-whatsapp
```

Run migrations and configure your first Meta App / WABA:

```
php artisan whatsapp:install --migrate
php artisan whatsapp:configure
```

`whatsapp:configure` prompts for Access Token, Meta App ID, App Secret, Verify Token and WABA ID. It validates credentials, subscribes the webhook, and persists all records in the database.

### Optional: publish assets for local customization

[](#optional-publish-assets-for-local-customization)

```
php artisan vendor:publish --tag=whatsapp-config
php artisan vendor:publish --tag=whatsapp-migrations
php artisan vendor:publish --tag=whatsapp-ai-guidelines  # Laravel Boost guidelines
```

---

Architecture
------------

[](#architecture)

All credentials (app secrets, access tokens, WABA IDs) are stored in the **database**, not in `.env`.

```
MetaApp ──── AccessToken ──────── BusinessAccount
                                       │
                                  ApiPhoneNumber
                                       │
                    ┌──────────────────┤
                    │                  │
                  Contact          WhatsAppMessage ── MediaElement
                                                   └── WhatsAppMessageError

```

ModelTablePurpose`MetaApp``whatsapp_meta_apps`Meta App credentials`AccessToken``whatsapp_access_tokens`OAuth tokens (many-to-many with WABA)`BusinessAccount``whatsapp_business_accounts`WABA data`ApiPhoneNumber``whatsapp_api_phone_numbers`Phone numbers`Contact``whatsapp_contacts`WhatsApp users (identified by `user_id` BSUID or `wa_id` phone)`WhatsAppMessage``whatsapp_messages`Sent and received messages`MediaElement``whatsapp_media_elements`Media files`Template``whatsapp_templates`Message templates---

Contacts &amp; Business-Scoped User IDs (BSUID)
-----------------------------------------------

[](#contacts--business-scoped-user-ids-bsuid)

From **March 31, 2026**, Meta includes a `user_id` (BSUID) in all webhook payloads. When a WhatsApp user enables the username feature, their phone number (`wa_id`) may be absent from webhooks.

The package handles this automatically:

- Contacts are identified by `user_id` (BSUID) when available; falls back to `wa_id` (phone)
- Outgoing messages use `to` (phone) when available; falls back to `recipient` (BSUID)
- `username` is stored on the contact when present

Contact fields:

FieldDescription`wa_id`Phone number (nullable — may be absent if user enabled username)`user_id`BSUID, e.g. `CO.13491208655302741918` (always present from 2026-03-31)`username`WhatsApp username e.g. `@johndoe` (optional)---

Sending Messages
----------------

[](#sending-messages)

```
use LaravelWhatsApp\Models\Contact;
use LaravelWhatsApp\Models\ApiPhoneNumber;
use LaravelWhatsApp\Models\MessageTypes\Text;
use LaravelWhatsApp\Models\MessageTypes\Image;

$from = ApiPhoneNumber::first();

// By phone number
$contact = Contact::firstOrCreate(
    ['api_phone_id' => $from->id, 'wa_id' => '5215512345678'],
    ['name' => 'Juan Perez']
);

// By BSUID (when phone is unavailable)
$contact = Contact::firstOrCreate(
    ['api_phone_id' => $from->id, 'user_id' => 'CO.13491208655302741918'],
    ['name' => 'Juan Perez']
);

// Send text
Text::make($contact, 'Hello!', false, $from)->send();

// Send image from URL
Image::createFromUrl($contact, $from, 'https://example.com/img.jpg', 'Caption')->send();

// Send image from uploaded media ID
Image::createFromId($contact, $from, $media->wa_media_id, 'Caption')->send();
```

### Template Messages

[](#template-messages)

```
use LaravelWhatsApp\Services\WhatsAppService;

$service = new WhatsAppService;
$service->sendTemplateMessage(
    to: $contact,
    templateName: 'order_followup',
    languageCode: 'es_CO',
    components: [
        [
            'type' => 'body',
            'parameters' => [
                ['type' => 'text', 'text' => 'Juan'],
                ['type' => 'text', 'text' => 'Order #1234'],
            ],
        ],
    ]
);
```

---

Receiving Messages (Webhooks)
-----------------------------

[](#receiving-messages-webhooks)

Routes are auto-registered:

MethodPathPurpose`GET``/whatsapp/webhook`Meta verification`POST``/whatsapp/webhook`Incoming messages &amp; status updatesThe POST route is protected by `VerifyMetaSignature` middleware (HMAC-SHA256). All stored `app_secret` values are checked — any match is accepted.

### Events

[](#events)

```
use LaravelWhatsApp\Events\WhatsAppMessageReceived;
use LaravelWhatsApp\Events\WhatsAppMessageStatusChange;

// In EventServiceProvider or via config:
Event::listen(WhatsAppMessageReceived::class, function ($event) {
    $event->message;        // WhatsAppMessage
    $event->media;          // MediaElement|null
    $event->mediaDownloaded; // bool
});

Event::listen(WhatsAppMessageStatusChange::class, function ($event) {
    $event->message; // WhatsAppMessage with updated status
});
```

Override default listeners via config:

```
// config/whatsapp.php
'listeners' => [
    'whatsapp_message_received'      => \App\Listeners\HandleIncoming::class,
    'whatsapp_message_status_change' => \App\Listeners\HandleStatus::class,
],
```

---

Media
-----

[](#media)

Incoming media is downloaded asynchronously via the `DownloadMedia` job. The `WhatsAppMessageReceived` event fires after the download completes.

```
use LaravelWhatsApp\Models\MediaElement;

// Upload media before sending
$media = MediaElement::create(['api_phone_number_id' => $from->id]);
$media->upload(storage_path('app/photo.jpg'));

// Download manually (usually handled by the job)
$media->download();
```

---

Configuration
-------------

[](#configuration)

Minimal `.env`:

```
APP_URL="https://example.com"
WHATSAPP_DOWNLOAD_DISK=public
```

Full options in `config/whatsapp.php`:

VariableDefaultDescription`WHATSAPP_GRAPH_VERSION``v24.0`Meta Graph API version`WHATSAPP_BASE_URL``https://graph.facebook.com`Graph API base URL`WHATSAPP_DOWNLOAD_DISK``local`Storage disk for media files`WHATSAPP_QUEUE_CONNECTION``sync`Queue connection`WHATSAPP_MEDIA_DOWNLOAD_QUEUE``default`Queue for `DownloadMedia` job`WHATSAPP_MARK_AS_READ_QUEUE``default`Queue for `MarkAsRead` job`WHATSAPP_MARK_MESSAGES_AS_READ_IMMEDIATELY``false`Auto-dispatch read job on inbound messages`WHATSAPP_EXPIRE_MEDIA_DAYS``15`Days before uploaded media expires### Custom Models

[](#custom-models)

```
// config/whatsapp.php
'contact_model'  => \App\Models\MyContact::class,
'apiphone_model' => \App\Models\MyApiPhoneNumber::class,
'message_model'  => \App\Models\MyWhatsAppMessage::class,
'media_model'    => \App\Models\MyMediaElement::class,
```

`message_model` lets you override the base `WhatsAppMessage` model used by internal webhook processing and relationships (for example, in `WhatsAppMessageError`).

`media_model` lets you override the base `MediaElement` model used in polymorphic relationships and internal media download/upload processes.

---

Webhook Security
----------------

[](#webhook-security)

For local tests, disable the middleware:

```
$this->withoutMiddleware(\LaravelWhatsApp\Http\Middleware\VerifyMetaSignature::class);
```

For integration tests, generate the signature:

```
$signature = hash_hmac('sha256', $rawBody, $metaApp->app_secret);
// Header: X-Hub-Signature-256: sha256=
```

---

Architecture Diagram
--------------------

[](#architecture-diagram)

 ```
flowchart TB
subgraph ORG["Your Organization"]
    subgraph META["Meta App"]
        CONFIG["Webhook URL · verify_token · app_secret"]
    end
    subgraph BACKEND["Laravel Backend"]
        VERIFY["GET /whatsapp/webhook\nValidates verify_token"]
        EVENTS["POST /whatsapp/webhook\nValidates X-Hub-Signature-256\nProcesses messages"]
        SEND["WhatsAppService\nUses Access Token"]
    end
end
subgraph CLIENTS["Business Portfolios"]
    WABA1["WABA 1"] --> PHONE1["+57 300 111 1111"]
    WABA2["WABA 2"] --> PHONE2["+57 300 222 2222"]
end
WABA1 -. events .-> CONFIG
WABA2 -. events .-> CONFIG
CONFIG --> EVENTS
CONFIG -- setup --> VERIFY
PHONE1 -. token .-> SEND
PHONE2 -. token .-> SEND
```

      Loading ---

Tests
-----

[](#tests)

```
composer test
composer test:coverage
```

---

License
-------

[](#license)

MIT

###  Health Score

48

—

FairBetter than 93% of packages

Maintenance92

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 70.8% 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 ~6 days

Total

35

Last Release

37d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/bd50c731012ef95d6ae90f5f4bd7e90575c1684815871330d52dfb5074a7d573?d=identicon)[IGedeon](/maintainers/IGedeon)

---

Top Contributors

[![sediardev](https://avatars.githubusercontent.com/u/80712465?v=4)](https://github.com/sediardev "sediardev (63 commits)")[![IGedeon](https://avatars.githubusercontent.com/u/694313?v=4)](https://github.com/IGedeon "IGedeon (26 commits)")

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/igedeon-laravel-whatsapp/health.svg)

```
[![Health](https://phpackages.com/badges/igedeon-laravel-whatsapp/health.svg)](https://phpackages.com/packages/igedeon-laravel-whatsapp)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.0k](/packages/simplestats-io-laravel-client)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M131](/packages/roots-acorn)[api-platform/laravel

API Platform support for Laravel

58171.6k14](/packages/api-platform-laravel)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1235.9k20](/packages/fleetbase-core-api)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)

PHPackages © 2026

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