irwan-runtuwene/driver-whatsapp

WABA On-Premise driver for BotMan

Installs: 1 564

Dependents: 0

Suggesters: 0

Security: 0

Stars: 7

Watchers: 2

Forks: 7

Open Issues: 0

pkg:composer/irwan-runtuwene/driver-whatsapp

v1.0.0 2026-01-26 10:03 UTC

This package is auto-updated.

Last update: 2026-01-26 10:18:31 UTC


README

BotMan driver to connect WhatsApp Business Cloud API with BotMan

WhatsApp Business Cloud API

This driver integrates with the WhatsApp Business Platform via the Cloud API. For API documentation, visit Meta for Developers - WhatsApp Business Platform

API Version: This driver uses v21.0 by default (latest stable as of January 2026). You can configure a different version if needed via WHATSAPP_API_VERSION environment variable.

Note: This driver also maintains backward compatibility with WhatsApp Business On-Premise API.

Installation & Setup

Install via Composer:

composer require irwan-runtuwene/driver-whatsapp

Configuration

BotMan Studio (Laravel)

Add the following entries to your .env file:

# WhatsApp Business Cloud API
WHATSAPP_API_VERSION=v21.0
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id
WHATSAPP_ACCESS_TOKEN=your_access_token
WHATSAPP_VERIFY_TOKEN=your_verify_token

# Optional: Business Account ID
WHATSAPP_BUSINESS_ACCOUNT_ID=your_business_account_id

# Error handling
WHATSAPP_THROW_EXCEPTIONS=true

# Media storage
WHATSAPP_MEDIA_TEMP_PATH=storage/app/whatsapp/media

Standalone BotMan

Pass configuration array when creating BotMan instance:

$config = [
    'whatsapp' => [
        'api_version' => 'v21.0',
        'phone_number_id' => 'your_phone_number_id',
        'access_token' => 'your_access_token',
        'verify_token' => 'your_verify_token',
        'throw_http_exceptions' => true,
    ]
];

$botman = BotManFactory::create($config);

Legacy On-Premise API Support

For backward compatibility with On-Premise API:

WHATSAPP_PARTNER=https://your-waba-host
WHATSAPP_TOKEN=your-bearer-token

Breaking Changes from Previous Version

Migration from On-Premise to Cloud API

If you're upgrading from the previous On-Premise-only version, you'll need to make the following changes:

1. Environment Variables (Required)

Old Configuration:

WHATSAPP_PARTNER=https://your-waba-host
WHATSAPP_TOKEN=your-bearer-token

New Configuration:

WHATSAPP_API_VERSION=v21.0
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id
WHATSAPP_ACCESS_TOKEN=your_access_token
WHATSAPP_VERIFY_TOKEN=your_verify_token

2. Webhook Payload Structure

The webhook payload structure has changed from On-Premise to Cloud API format:

Old Format (On-Premise):

{
  "messages": [{
    "from": "1234567890",
    "type": "text",
    "text": {"body": "Hello"}
  }],
  "contacts": [...]
}

New Format (Cloud API):

{
  "entry": [{
    "changes": [{
      "value": {
        "messages": [{
          "from": "1234567890",
          "type": "text",
          "text": {"body": "Hello"}
        }],
        "contacts": [...],
        "metadata": {...}
      }
    }]
  }]
}

Note: The driver automatically handles both formats, so no code changes are needed on your end.

3. Message ID Access

Old Way:

// This may not work consistently
$messageId = $message->getPayload()->get('id');

New Way:

// Reliable for Cloud API
$payload = $message->getPayload();
$messageId = $payload->get('messages')[0]['id'] ?? null;

// Or from the event directly
$messageId = $message->getPayload()->get('entry')[0]['changes'][0]['value']['messages'][0]['id'] ?? null;

4. Media Handling

Media handling has significantly improved but requires different approach:

Old Way (On-Premise):

// Media URLs were directly accessible
$mediaUrl = $message->getPayload()->get('image')['url'];

New Way (Cloud API):

// Media requires a two-step process
$media = $message->getPayload()->get('media');
if ($media) {
    $driver = $bot->getDriver();
    
    // Step 1: Get media URL
    $mediaInfo = $driver->getMediaUrl($media['id']);
    
    // Step 2: Download media
    $driver->downloadMedia($mediaInfo['url'], $savePath);
}

5. Interactive Messages (New Feature)

The previous version had limited interactive message support. The new version includes full support:

Buttons (Now Available):

use BotMan\Drivers\Whatsapp\Extensions\ButtonTemplate;
use BotMan\Drivers\Whatsapp\Extensions\ElementButton;

$template = ButtonTemplate::create('Choose an option:')
    ->addButton(ElementButton::create('option_1', 'Option 1'))
    ->addButton(ElementButton::create('option_2', 'Option 2'));

$bot->reply($template);

Lists (Now Available):

use BotMan\Drivers\Whatsapp\Extensions\ListTemplate;
use BotMan\Drivers\Whatsapp\Extensions\ListSection;
use BotMan\Drivers\Whatsapp\Extensions\ListRow;

$section = ListSection::create('Products')
    ->addRow(ListRow::create('prod_1', 'Product 1', 'Description'));

$template = ListTemplate::create('Our Products', 'View Catalog')
    ->addSection($section);

$bot->reply($template);

6. Template Messages

Template message structure has changed:

Old Way:

// Limited or no template support

New Way:

use BotMan\Drivers\Whatsapp\Extensions\TemplateMessage;

$template = TemplateMessage::create('order_confirmation', 'en_US')
    ->addBodyParameters(['John Doe', 'ORD-12345', '$99.99']);

$bot->reply($template);

7. New Features Not in Previous Version

The following features are entirely new and have no equivalent in the On-Premise version:

  • Reactions - React to messages with emojis
  • Reply Context - Quote/reply to specific messages
  • Mark as Read - Send read receipts
  • Contact Messages - Share vCard contacts
  • Media Upload - Upload media to WhatsApp CDN
  • Webhook Verification - Automatic webhook challenge response

8. Error Response Format

Error responses now use Cloud API format:

Old Format:

{
  "errors": {
    "code": "...",
    "title": "..."
  }
}

New Format:

{
  "error": {
    "message": "...",
    "type": "...",
    "code": 123,
    "fbtrace_id": "..."
  }
}

Note: The driver's exception handling automatically adapts to both formats.

Features

✅ Fully Supported

  • Text Messages - Send and receive text messages
  • Media Messages - Images, videos, audio, documents, stickers
  • Interactive Messages
    • Buttons (up to 3 buttons)
    • Lists (up to 10 items per section)
  • Template Messages - Send pre-approved message templates
  • Location Messages - Send and receive location data
  • Contact Messages - Share contact cards
  • Reactions - React to messages with emojis
  • Reply Context - Reply to specific messages
  • Media Management - Upload and download media files
  • Message Status - Mark messages as read
  • Webhook Verification - Automatic webhook verification
  • WhatsApp Flows - Interactive multi-step experiences with forms and screens

Usage Examples

Text Messages

$botman->hears('hello', function ($bot) {
    $bot->reply('Hello! How can I help you?');
});

Button Messages

use BotMan\Drivers\Whatsapp\Extensions\ButtonTemplate;
use BotMan\Drivers\Whatsapp\Extensions\ElementButton;

$botman->hears('menu', function ($bot) {
    $template = ButtonTemplate::create('Choose an option:')
        ->addButton(ElementButton::create('option_1', 'Option 1'))
        ->addButton(ElementButton::create('option_2', 'Option 2'))
        ->addButton(ElementButton::create('option_3', 'Option 3'));
    
    $bot->reply($template);
});

List Messages

use BotMan\Drivers\Whatsapp\Extensions\ListTemplate;
use BotMan\Drivers\Whatsapp\Extensions\ListSection;
use BotMan\Drivers\Whatsapp\Extensions\ListRow;

$botman->hears('catalog', function ($bot) {
    $section = ListSection::create('Products')
        ->addRow(ListRow::create('prod_1', 'Product 1', 'Description 1'))
        ->addRow(ListRow::create('prod_2', 'Product 2', 'Description 2'));
    
    $template = ListTemplate::create('Our Products', 'View Catalog')
        ->addSection($section);
    
    $bot->reply($template);
});

Template Messages

use BotMan\Drivers\Whatsapp\Extensions\TemplateMessage;

$botman->hears('order confirmation', function ($bot) {
    $template = TemplateMessage::create('order_confirmation', 'en_US')
        ->addBodyParameters(['John Doe', 'ORD-12345', '$99.99']);
    
    $bot->reply($template);
});

Media Messages

use BotMan\Drivers\Whatsapp\Extensions\MediaTemplate;

// Send image
$botman->hears('send image', function ($bot) {
    $media = MediaTemplate::create(MediaTemplate::TYPE_IMAGE)
        ->link('https://example.com/image.jpg')
        ->caption('Check this out!');
    
    $bot->reply($media);
});

// Send document
$botman->hears('send pdf', function ($bot) {
    $media = MediaTemplate::create(MediaTemplate::TYPE_DOCUMENT)
        ->link('https://example.com/document.pdf')
        ->filename('Document.pdf')
        ->caption('Here is the document');
    
    $bot->reply($media);
});

Location Messages

use BotMan\Drivers\Whatsapp\Extensions\LocationMessage;

$botman->hears('location', function ($bot) {
    $location = LocationMessage::create(37.7749, -122.4194)
        ->name('San Francisco Office')
        ->address('123 Market St, San Francisco, CA');
    
    $bot->reply($location);
});

Reactions

use BotMan\Drivers\Whatsapp\Extensions\ReactionMessage;

$botman->receivedMessage(function ($bot, $message) {
    // React to the message with a thumbs up
    $messageId = $message->getPayload()->get('messages')[0]['id'];
    $reaction = ReactionMessage::create($messageId, '👍');
    
    $bot->reply($reaction);
});

WhatsApp Flows

WhatsApp Flows allow you to create interactive, multi-step experiences within WhatsApp.

use BotMan\Drivers\Whatsapp\Extensions\FlowTemplate;

// Send a flow message
$botman->hears('start survey', function ($bot) {
    $flow = FlowTemplate::create(
        'your_flow_id',           // Flow ID from WhatsApp Manager
        'Start Survey',            // Button text
        'Please complete our customer satisfaction survey'
    )
    ->header('Customer Survey')
    ->footer('Takes only 2 minutes')
    ->navigate('welcome_screen', ['customer_id' => '12345'])
    ->mode('published');  // or 'draft' for testing
    
    $bot->reply($flow);
});

// Handle flow responses
$botman->receivedMessage(function ($bot, $message) {
    $payload = $message->getPayload();
    
    if ($flowResponse = $payload->get('flow_response')) {
        $responseData = json_decode($flowResponse['response_json'], true);
        
        // Process the flow response data
        $bot->reply('Thank you for completing the survey!');
        
        // Access flow data
        $name = $flowResponse['name'];
        $data = $responseData;  // Contains user's form submissions
    }
});

// Data exchange flow
$botman->hears('update profile', function ($bot) {
    $flow = FlowTemplate::create(
        'profile_flow_id',
        'Update Profile',
        'Update your account information'
    )
    ->dataExchange([
        'current_name' => 'John Doe',
        'current_email' => 'john@example.com',
    ])
    ->mode('published');
    
    $bot->reply($flow);
});

Reply to Messages

$botman->hears('quote me', function ($bot, $message) {
    $messageId = $message->getPayload()->get('messages')[0]['id'];
    
    // Use the driver to set reply context
    $driver = $bot->getDriver();
    $driver->replyTo($messageId);
    
    $bot->reply('This is a reply to your message!');
});

Media Download

$botman->receivedMessage(function ($bot, $message) {
    $payload = $message->getPayload();
    
    if ($media = $payload->get('media')) {
        $driver = $bot->getDriver();
        
        // Get media URL
        $mediaInfo = $driver->getMediaUrl($media['id']);
        
        // Download media
        $savePath = storage_path("app/whatsapp/media/{$media['id']}");
        $driver->downloadMedia($mediaInfo['url'], $savePath);
        
        $bot->reply('Media downloaded successfully!');
    }
});

Mark as Read

$botman->receivedMessage(function ($bot, $message) {
    $messageId = $message->getPayload()->get('messages')[0]['id'];
    $driver = $bot->getDriver();
    $driver->markAsRead($messageId);
});

Security Vulnerabilities

If you discover a security vulnerability, please send an e-mail to stefanus.irwant@gmail.com. All security vulnerabilities will be promptly addressed.

License

This driver is open-source software licensed under the MIT license.