Laravel package for integrating Meta WhatsApp Business Cloud API, providing:
- CRUD Templates for WhatsApp Business
- Send messages (text, media, template, interactive, location, document)
- Multi-account support (auto-pick default if only one)
- Broadcast to millions of recipients (chunking, scheduling, job queue)
- Webhook to update message status (sent, delivered, read, failed)
- Queue + Retry for reliability
- Install:
composer require elgibor-solution/laravel-whatsapp-meta:*
- Publish config & migrations:
php artisan vendor:publish --tag=whatsapp-config
php artisan vendor:publish --tag=whatsapp-migrations
php artisan migrate
- Add to scheduler:
// routes/console.php
$schedule->command('whatsapp:broadcast-run')->everyMinute();
WHATSAPP_SINGLE_ACCOUNT=true
WHATSAPP_NAME=default
WHATSAPP_PHONE_NUMBER_ID=YOUR_PHONE_ID
WHATSAPP_ACCESS_TOKEN=YOUR_LONG_LIVED_TOKEN
WHATSAPP_WABA_ID=YOUR_WABA_ID
WHATSAPP_WEBHOOK_VERIFY_TOKEN=change-me
If multiple accounts are needed:
- Insert rows into
whatsapp_accounts
table (migration provided). - Mark one with
is_default = 1
as the default account.
All endpoints are available with prefix /whatsapp/*
:
GET /whatsapp/webhook
β webhook verificationPOST /whatsapp/webhook
β handle message status updatesPOST /whatsapp/messages/send
β send a messageGET/POST/PUT/DELETE /whatsapp/templates
β manage templatesPOST /whatsapp/broadcasts
β create broadcastPOST /whatsapp/broadcasts/{id}/schedule
β schedule broadcastPOST /whatsapp/broadcasts/{id}/pause|resume
β control broadcast
use WhatsApp;
use ESolution\WhatsApp\Models\WhatsappAccount;
$acc = WhatsappAccount::resolve();
// 1. Send text
WhatsApp::sendText($acc, '08123456789', 'Hello from Cloud API!');
// 2. Send template
WhatsApp::sendTemplate($acc, '08123456789', 'order_update', 'en', [
['type'=>'body','parameters'=>[['type'=>'text','text'=>'John']]]
]);
// 3. Send media
WhatsApp::sendMedia($acc, '08123456789', 'image', [
'link'=>'https://example.com/img.jpg',
'caption'=>'Promo'
]);
// 4. Send location
WhatsApp::sendLocation($acc, '08123456789', -6.2, 106.8, 'Office', 'Jakarta');
// 5. Send interactive
WhatsApp::sendInteractive($acc, '08123456789', [
'type'=>'list',
'header'=>['type'=>'text','text'=>'Menu'],
'body'=>['text'=>'Choose option'],
'footer'=>['text'=>'E-Solution'],
'action'=>[
'button'=>'View',
'sections'=>[
['title'=>'Products','rows'=>[
['id'=>'prod1','title'=>'Product 1','description'=>'Description 1'],
['id'=>'prod2','title'=>'Product 2','description'=>'Description 2'],
]]
]
]
]);
$acc = WhatsappAccount::resolve();
// List
$list = WhatsApp::listTemplates($acc);
// Create
$tpl = WhatsApp::createTemplate($acc, [
'name'=>'promo_aug',
'category'=>'MARKETING',
'language'=>'en',
'components'=>[['type'=>'BODY','text'=>'Hello {{1}}, August promo!']]
]);
// Delete
WhatsApp::deleteTemplate($acc, 'promo_aug', 'en');
POST /whatsapp/broadcasts
{
"name": "Promo August",
"type": "template",
"payload": {
"name": "promo_aug",
"language": "en",
"components": [
{ "type": "body", "parameters": [ { "type": "text", "text": "Customer" } ] }
]
},
"recipients": ["0811111111","0812222222","0813333333"],
"chunk_size": 2000,
"rate_per_min": 6000
}
POST /whatsapp/broadcasts/1/schedule
{ "scheduled_at": "2025-08-24 22:00:00" }
php artisan schedule:run
Broadcasts will be dispatched in chunks using SendBroadcastChunkJob
with respect to chunk_size
and rate_per_min
.
- URL:
/whatsapp/webhook
- Verify: Meta calls
GET /webhook?hub_mode=subscribe&hub_verify_token=xxx&hub_challenge=1234
- Status: Meta sends
POST
updates with message status (sent
,delivered
,read
,failed
). - Call Permission: Meta sends
POST
updates with call_permission_reply status (accept
,reject
).
Statuses are saved to:
whatsapp_messages
whatsapp_broadcast_recipients
Call permission are broadcast through event:
whatsapp.call_permission.updated
You need to create your own event listener and register it at EventServiceProvider
// app/Providers/EventServiceProvider.php
protected $listen = [
'whatsapp.call_permission.updated' => [
\App\Listeners\HandleCallPermissionUpdated::class,
],
];
- Messages are sent via
SendMessageJob
. - Broadcasts are handled via
SendBroadcastChunkJob
. - Use Redis / SQS / Horizon queues for scaling.
- Automatic retry:
tries = 3
,backoff = 30s
.
- Always use APPROVED templates for outbound messages beyond 24h window.
- Respect WABA tier rate limits.
rate_per_min
only throttles locally. - Media must be public URLs.
- Phone numbers are normalized: leading
0
β62
. Adjust if needed. - Store and log Graph API responses for error analysis.
Need professional help or want to move faster? Hire the E-Solution / Elgibor team for integration, audits, or custom features.
π§ [email protected]
If this package saves you time, consider supporting development β€οΈ