art-fatal / wasenderapi-symfony
Symfony bundle for WasenderAPI – send WhatsApp messages, manage contacts, groups, sessions, and handle webhooks
Package info
github.com/art-fatal/wasenderapi-symfony
Type:symfony-bundle
pkg:composer/art-fatal/wasenderapi-symfony
Requires
- php: >=7.3
- guzzlehttp/guzzle: ^6.5 || ^7.0
- symfony/config: ^4.4 || ^5.0 || ^6.0 || ^7.0
- symfony/dependency-injection: ^4.4 || ^5.0 || ^6.0 || ^7.0
- symfony/event-dispatcher: ^4.4 || ^5.0 || ^6.0 || ^7.0
- symfony/http-foundation: ^4.4 || ^5.0 || ^6.0 || ^7.0
- symfony/http-kernel: ^4.4 || ^5.0 || ^6.0 || ^7.0
- symfony/routing: ^4.4 || ^5.0 || ^6.0 || ^7.0
Requires (Dev)
- phpunit/phpunit: ^8.5 || ^9.0
This package is auto-updated.
Last update: 2026-03-25 06:13:33 UTC
README
Symfony bundle for WasenderAPI – send WhatsApp messages, manage contacts, groups, sessions, and handle webhooks with Symfony best practices.
Requires PHP >= 7.3 | Compatible with Symfony 4.4, 5.x, 6.x, 7.x
Features
- Send text, image, video, document, audio, sticker, contact and location messages
- Quoted messages, mentions, and presence updates
- Edit and delete messages
- Contact management (info, profile picture, block/unblock, WhatsApp check)
- Group management (create, metadata, participants, settings, invites)
- Session management (CRUD, connect, disconnect, QR code, API key regeneration)
- Media upload (file or base64) and decryption
- Webhook handling with automatic event dispatching
- Rate-limit retry support (HTTP 429)
- Full DTO support for type-safe payloads
Installation
composer require wasenderapi/wasenderapi-symfony
Register the bundle
If your application does not use Symfony Flex, add the bundle to config/bundles.php:
return [ // ... WasenderApi\SymfonyBundle\WasenderApiBundle::class => ['all' => true], ];
Configuration
Create config/packages/wasenderapi.yaml:
wasenderapi: api_key: '%env(WASENDERAPI_API_KEY)%' personal_access_token: '%env(WASENDERAPI_PERSONAL_ACCESS_TOKEN)%' base_url: 'https://www.wasenderapi.com/api' webhook: secret: '%env(WASENDERAPI_WEBHOOK_SECRET)%' path: '/wasender/webhook' signature_header: 'x-webhook-signature'
Add to your .env file:
WASENDERAPI_API_KEY=your_api_key_here WASENDERAPI_PERSONAL_ACCESS_TOKEN=your_personal_token_here WASENDERAPI_WEBHOOK_SECRET=your_webhook_secret_here
Import webhook route
Add to config/routes.yaml:
wasenderapi_webhook: resource: '@WasenderApiBundle/Resources/config/routing.xml'
Usage
Dependency injection (recommended)
use WasenderApi\SymfonyBundle\Client\WasenderApiClient; class WhatsAppController { private $wasender; public function __construct(WasenderApiClient $wasender) { $this->wasender = $wasender; } public function send() { $this->wasender->sendText('1234567890', 'Hello from Symfony!'); } }
Direct instantiation
Useful for managing multiple sessions with different API keys:
use WasenderApi\SymfonyBundle\Client\WasenderApiClient; $client = new WasenderApiClient('your_api_key_here'); $client->sendText('1234567890', 'Hello!');
Sending Messages
All message methods support both direct parameters and DTOs. All return an associative array.
Text
use WasenderApi\SymfonyBundle\DTO\SendTextMessageData; $client->sendText('123', 'Hello!'); // or with DTO $client->sendText(new SendTextMessageData('123', 'Hello!'));
Image
use WasenderApi\SymfonyBundle\DTO\SendImageMessageData; $client->sendImage('123', 'https://example.com/image.png', 'Caption'); // or $client->sendImage(new SendImageMessageData('123', 'https://example.com/image.png', 'Caption'));
Video
$client->sendVideo('123', 'https://example.com/video.mp4', 'Watch this');
Document
$client->sendDocument('123', 'https://example.com/file.pdf', 'My caption', 'file.pdf');
Audio
$client->sendAudio('123', 'https://example.com/audio.mp3');
Sticker
$client->sendSticker('123', 'https://example.com/sticker.webp');
Contact
$client->sendContact('123', 'John Doe', '+1234567890');
Location
$client->sendLocation('123', 48.8566, 2.3522, 'Paris', '1 Rue de Rivoli');
Quoted message
$client->sendQuotedMessage('123', 42, 'Replying to your message');
Mentions
$client->sendMessageWithMentions('group@g.us', 'Hello @user', ['user@s.whatsapp.net']);
Edit / Delete / Info
$client->editMessage(123, 'Updated text'); $client->deleteMessage(123); $client->getMessageInfo(123);
Retry on rate limit
Use RetryConfig on send-message methods to automatically retry on HTTP 429:
use WasenderApi\SymfonyBundle\DTO\RetryConfig; $retry = new RetryConfig(true, 3); $client->sendText('123', 'Hello!', [], $retry);
Contact Management
$client->getContacts(); $client->getContactInfo('1234567890'); $client->getContactProfilePicture('1234567890'); $client->blockContact('1234567890'); $client->unblockContact('1234567890'); $client->checkIfOnWhatsapp('+1234567890');
Group Management
$client->createGroup('My Group', ['user1@s.whatsapp.net']); $client->getGroups(); $client->getGroupMetadata('group-jid'); $client->getGroupParticipants('group-jid'); $client->addGroupParticipants('group-jid', ['user@s.whatsapp.net']); $client->removeGroupParticipants('group-jid', ['user@s.whatsapp.net']); $client->updateGroupParticipants('group-jid', 'promote', ['user@s.whatsapp.net']); $client->updateGroupSettings('group-jid', ['setting' => 'value']); $client->getGroupInviteInfo('invite-code'); $client->leaveGroup('group-jid'); $client->acceptGroupInvite('invite-code'); $client->getGroupInviteLink('group-jid'); $client->getGroupProfilePicture('group-jid');
Session Management
These endpoints require a personal access token.
$client->getAllWhatsAppSessions(); $client->createWhatsAppSession(['name' => 'My Session']); $client->getWhatsAppSessionDetails(1); $client->updateWhatsAppSession(1, ['name' => 'Renamed']); $client->deleteWhatsAppSession(1); $client->connectWhatsAppSession(1); $client->getWhatsAppSessionQrCode(1); $client->disconnectWhatsAppSession(1); $client->regenerateApiKey(1); $client->getSessionStatus('1'); $client->getSessionUserInfo();
Media
// Upload from base64 $client->uploadMediaFile('data:image/png;base64,AAA...', 'image/png'); // Upload from file path $client->uploadMediaFile('/path/to/image.png'); // Decrypt media $client->decryptMediaFile($encryptedPayload);
Presence
$client->sendPresenceUpdate('user@s.whatsapp.net', 'composing'); $client->sendPresenceUpdate('user@s.whatsapp.net', 'recording', 2000);
Webhook Handling
The bundle automatically registers a webhook endpoint. When WasenderAPI sends a webhook, the controller verifies the signature and dispatches a Symfony event.
Listening for events
Create an event subscriber:
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use WasenderApi\SymfonyBundle\Event\MessagesUpserted; use WasenderApi\SymfonyBundle\Event\MessageReceived; use WasenderApi\SymfonyBundle\Event\CallReceived; class WasenderEventSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ MessagesUpserted::class => 'onMessagesUpserted', MessageReceived::class => 'onMessageReceived', CallReceived::class => 'onCallReceived', ]; } public function onMessagesUpserted(MessagesUpserted $event): void { $payload = $event->getPayload(); // Handle upserted messages } public function onMessageReceived(MessageReceived $event): void { $payload = $event->getPayload(); // Handle received message } public function onCallReceived(CallReceived $event): void { $payload = $event->getPayload(); // Handle incoming call } }
Available events
| Webhook type | Event class |
|---|---|
chats.upsert |
ChatsUpserted |
chats.update |
ChatsUpdated |
chats.delete |
ChatsDeleted |
contacts.upsert |
ContactsUpserted |
contacts.update |
ContactsUpdated |
groups.upsert |
GroupsUpserted |
groups.update |
GroupsUpdated |
group-participants.update |
GroupParticipantsUpdated |
messages.upsert |
MessagesUpserted |
messages.update |
MessagesUpdated |
messages.delete |
MessagesDeleted |
messages.reaction |
MessagesReaction |
message-receipt.update |
MessageReceiptUpdated |
message.sent |
MessageSent |
messages.received |
MessageReceived |
messages-personal.received |
PersonalMessageReceived |
messages-group.received |
GroupMessageReceived |
messages-newsletter.received |
NewsletterMessageReceived |
session.status |
SessionStatus |
qrcode.updated |
QrCodeUpdated |
call.received |
CallReceived |
poll.results |
PollResults |
Unmapped event types dispatch WasenderWebhookEvent with getEventName() and getPayload().
Error Handling
All API errors throw WasenderApiException:
use WasenderApi\SymfonyBundle\Exception\WasenderApiException; try { $client->sendText('123', 'Hello'); } catch (WasenderApiException $e) { $e->getMessage(); // Error description $e->getCode(); // HTTP status code $e->getResponse(); // Parsed JSON response (array or null) }
Testing
composer install vendor/bin/phpunit
License
MIT