| Install | |
|---|---|
composer require wallacemartinss/filament-whatsapp-conector |
|
| Latest Version: | 2.0.0 |
| PHP: | ^8.2 |
A Filament v5 plugin for WhatsApp integration using Evolution API v2.

![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
composer require wallacemartinss/filament-whatsapp-conector
php artisan vendor:publish --tag="filament-evolution-config"
php artisan vendor:publish --tag="filament-evolution-migrations"
php artisan migrate
Add the plugin to your Filament Panel Provider:
use WallaceMartinss\FilamentEvolution\FilamentEvolutionPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentEvolutionPlugin::make(),
]);
}
Add the plugin's views and source files to your Filament theme CSS file (e.g., resources/css/filament/admin/theme.css):
@import '../../../../vendor/filament/filament/resources/css/theme.css';
@source '../../../../app/Filament/**/*';
@source '../../../../resources/views/filament/**/*';
/* Add these lines for Filament Evolution */
@source '../../../../vendor/wallacemartinss/filament-whatsapp-conector/resources/views/**/*';
@source '../../../../vendor/wallacemartinss/filament-whatsapp-conector/src/**/*';
Then rebuild your assets:
npm run build
You can customize which resources are available in the panel:
FilamentEvolutionPlugin::make()
->viewMessageHistory() // Enable message history resource
->viewWebhookLogs() // Enable webhook logs resource
| Method | Default | Description |
|---|---|---|
whatsappInstanceResource(bool) |
true |
Show/hide the WhatsApp Instances resource |
viewMessageHistory(bool) |
false |
Show/hide the Message History resource |
viewWebhookLogs(bool) |
false |
Show/hide the Webhook Logs resource |
FilamentEvolutionPlugin::make()
->whatsappInstanceResource() // Show instances (default: true)
->viewMessageHistory() // Show message history
->viewWebhookLogs() // Show webhook logs
# Evolution API Connection (Required)
EVOLUTION_URL=https://your-evolution-api.com
EVOLUTION_API_KEY=your_api_key
# Webhook Configuration (Required for receiving events)
EVOLUTION_WEBHOOK_URL=https://your-app.com/api/webhooks/evolution
EVOLUTION_WEBHOOK_SECRET=your_secret_key
EVOLUTION_WEBHOOK_PATH=api/webhooks/evolution
# Storage Options (Optional - defaults to true)
EVOLUTION_STORE_WEBHOOKS=true
EVOLUTION_STORE_MESSAGES=true
# Instance Settings (Optional)
EVOLUTION_QRCODE_EXPIRES=30
EVOLUTION_DEFAULT_INSTANCE=your_instance_id
The plugin uses Laravel queues to process webhooks and send messages. Make sure you have a queue worker running:
php artisan queue:work
For production, use a process manager like Supervisor to keep the worker running. See the Laravel Queue Documentation for more details.
All other settings are in config/filament-evolution.php. Publish and customize:
php artisan vendor:publish --tag="filament-evolution-config"
Key configuration options:
// config/filament-evolution.php
return [
// Queue settings
'queue' => [
'enabled' => true,
'connection' => null, // null = default connection
'name' => 'default', // queue name
],
// Storage settings
'storage' => [
'webhooks' => true, // save webhooks to database
'messages' => true, // save messages to database
],
// Cleanup policy (automatic deletion of old records)
'cleanup' => [
'webhooks_days' => 30, // delete webhooks older than 30 days
'messages_days' => 90, // delete messages older than 90 days
],
// Instance defaults
'instance' => [
'reject_call' => false,
'always_online' => false,
// ...
],
// Multi-tenancy
'tenancy' => [
'enabled' => false,
'column' => 'team_id',
'table' => 'teams',
'model' => 'App\\Models\\Team',
],
];
The plugin includes a cleanup command to remove old records:
# Run cleanup with config settings
php artisan evolution:cleanup
# Preview what would be deleted (dry run)
php artisan evolution:cleanup --dry-run
# Override config settings
php artisan evolution:cleanup --webhooks-days=7 --messages-days=30
Add to your routes/console.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('evolution:cleanup')->daily();
| Setting | Description |
|---|---|
| Reject Calls | Automatically reject incoming calls |
| Message on Call | Message sent when rejecting calls |
| Ignore Groups | Don't process messages from groups |
| Always Online | Keep WhatsApp status as online |
| Read Messages | Automatically mark messages as read |
| Read Status | Automatically view status updates |
| Sync Full History | Sync all message history on connection |
The plugin provides three ways to send WhatsApp messages:
The SendWhatsappMessageAction can be used in any Filament page, resource, or widget.
use WallaceMartinss\FilamentEvolution\Actions\SendWhatsappMessageAction;
// In a table
public function table(Table $table): Table
{
return $table
->actions([
SendWhatsappMessageAction::make(),
]);
}
// In a page header
protected function getHeaderActions(): array
{
return [
SendWhatsappMessageAction::make(),
];
}
SendWhatsappMessageAction::make()
->number('5511999999999') // Default phone number
->instance($instanceId) // Default instance
->message('Hello World!') // Default message
Get the phone number automatically from the record:
// Using attribute name
SendWhatsappMessageAction::make()
->numberFrom('phone'),
// Using dot notation for relationships
SendWhatsappMessageAction::make()
->numberFrom('contact.phone'),
// Using closure for custom logic
SendWhatsappMessageAction::make()
->numberFrom(fn ($record) => $record->celular ?? $record->telefone),
// Also set instance from record
SendWhatsappMessageAction::make()
->numberFrom('phone')
->instanceFrom('whatsapp_instance_id'),
SendWhatsappMessageAction::make()
->hideInstanceSelect() // Hide instance selector
->hideNumberInput() // Hide phone number input
->textOnly() // Only allow text messages (hide file upload)
use WallaceMartinss\FilamentEvolution\Enums\MessageTypeEnum;
SendWhatsappMessageAction::make()
->allowedTypes([
MessageTypeEnum::TEXT,
MessageTypeEnum::IMAGE,
]);
SendWhatsappMessageAction::make()
->disk('s3') // Use S3 for file uploads
For programmatic message sending from anywhere in your application:
use WallaceMartinss\FilamentEvolution\Facades\Whatsapp;
// Send text
Whatsapp::sendText($instanceId, '5511999999999', 'Hello!');
// Send image with caption
Whatsapp::sendImage($instanceId, '5511999999999', 'path/to/image.jpg', 'Check this out!');
// Send video with caption
Whatsapp::sendVideo($instanceId, '5511999999999', 'path/to/video.mp4', 'Watch this!');
// Send audio
Whatsapp::sendAudio($instanceId, '5511999999999', 'path/to/audio.mp3');
// Send document
Whatsapp::sendDocument($instanceId, '5511999999999', 'path/to/file.pdf', 'report.pdf', 'Monthly Report');
// Send location
Whatsapp::sendLocation($instanceId, '5511999999999', -23.5505, -46.6333, 'My Office', 'São Paulo, SP');
// Send contact card
Whatsapp::sendContact($instanceId, '5511999999999', 'John Doe', '+5511888888888');
// Generic send method
Whatsapp::send($instanceId, '5511999999999', 'text', 'Hello World!');
Whatsapp::send($instanceId, '5511999999999', 'image', 'path/to/image.jpg', ['caption' => 'Nice!']);
Add the CanSendWhatsappMessage trait to integrate message sending into your business logic:
use WallaceMartinss\FilamentEvolution\Concerns\CanSendWhatsappMessage;
class InvoiceService
{
use CanSendWhatsappMessage;
public function sendPaymentReminder(Invoice $invoice): void
{
$this->sendWhatsappText(
$invoice->customer->phone,
"Hello {$invoice->customer->name}, your invoice #{$invoice->number} is due on {$invoice->due_date->format('d/m/Y')}."
);
}
public function sendInvoicePdf(Invoice $invoice): void
{
$this->sendWhatsappDocument(
$invoice->customer->phone,
$invoice->pdf_path,
"invoice-{$invoice->number}.pdf",
"Your invoice is ready!"
);
}
public function sendPromoImage(Customer $customer, string $imagePath): void
{
$this->sendWhatsappImage(
$customer->phone,
$imagePath,
"Special promotion just for you! 🎉"
);
}
}
| Method | Description |
|---|---|
sendWhatsappText($number, $message) |
Send text message |
sendWhatsappImage($number, $path, $caption) |
Send image |
sendWhatsappVideo($number, $path, $caption) |
Send video |
sendWhatsappAudio($number, $path) |
Send audio |
sendWhatsappDocument($number, $path, $fileName, $caption) |
Send document |
sendWhatsappLocation($number, $lat, $lng, $name, $address) |
Send location |
sendWhatsappContact($number, $contactName, $contactNumber) |
Send contact card |
sendWhatsappMessage($number, $type, $content, $options) |
Generic send method |
hasWhatsappInstance() |
Check if an instance is available |
getConnectedWhatsappInstances() |
Get all connected instances |
Override getWhatsappInstanceId() to use a specific instance:
class TenantInvoiceService
{
use CanSendWhatsappMessage;
protected function getWhatsappInstanceId(): ?string
{
// Use tenant's specific WhatsApp instance
return auth()->user()->tenant->whatsapp_instance_id;
}
}
The plugin supports both local and cloud storage (S3, etc.) for media files.
EVOLUTION_MEDIA_DISK=public
EVOLUTION_MEDIA_DIRECTORY=whatsapp-media
EVOLUTION_MEDIA_MAX_SIZE=16384
// Using the Facade with S3
Whatsapp::sendDocument($instanceId, $number, 'documents/report.pdf', 'report.pdf', null, 's3');
// Using the Action with custom disk
SendWhatsappMessageAction::make()->disk('s3');
The plugin includes a webhook endpoint to receive events from Evolution API.
| Event | Description |
|---|---|
APPLICATION_STARTUP |
API started |
QRCODE_UPDATED |
New QR code generated |
CONNECTION_UPDATE |
Connection status changed |
NEW_TOKEN |
New authentication token |
SEND_MESSAGE |
Message sent |
PRESENCE_UPDATE |
Contact online/offline |
MESSAGES_UPSERT |
New message received |
Configure this URL in your Evolution API instance settings:
https://your-app.com/api/webhooks/evolution
Note: The webhook route is
/api/webhooks/evolutionby default. Make sure yourEVOLUTION_WEBHOOK_URLenv variable matches this path.
The plugin supports Filament's native multi-tenancy. When enabled:
Edit the config/filament-evolution.php file:
'tenancy' => [
'enabled' => true,
'column' => 'team_id',
'table' => 'teams',
'model' => 'App\\Models\\Team',
'column_type' => 'uuid', // 'uuid' or 'id'
],
For advanced use cases, you can use the Evolution client directly:
use WallaceMartinss\FilamentEvolution\Services\EvolutionClient;
$client = app(EvolutionClient::class);
// Create instance
$response = $client->createInstance('my-instance', '5511999999999', true, [
'reject_call' => true,
'always_online' => true,
]);
// Get connection state
$state = $client->getConnectionState('my-instance');
// Send text message
$client->sendText('my-instance', '5511999999999', 'Hello World!');
// Send image (path is base64 encoded by the service)
$client->sendImage('my-instance', '5511999999999', $base64Content, 'image.jpg', 'Check this!');
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.