Skip to content

Interactive Messages

Send interactive messages including buttons, lists, and polls to engage users.

Button Messages

Basic Buttons

use Lynkbyte\EvolutionApi\Facades\EvolutionApi;

$response = EvolutionApi::for('my-instance')
    ->messages()
    ->sendButtons(
        number: '5511999999999',
        title: 'Choose an option',
        description: 'Please select one of the options below',
        buttons: [
            ['buttonId' => 'opt1', 'buttonText' => 'Option 1'],
            ['buttonId' => 'opt2', 'buttonText' => 'Option 2'],
            ['buttonId' => 'opt3', 'buttonText' => 'Option 3'],
        ],
        footer: 'Tap a button to continue'
    );

Button Limits

  • Maximum 3 buttons per message
  • Button text: max 20 characters
  • Button ID: used to identify which button was pressed

List Messages

Basic List

use Lynkbyte\EvolutionApi\DTOs\Message\SendListMessageDto;

$response = EvolutionApi::for('my-instance')
    ->messages()
    ->sendList([
        'number' => '5511999999999',
        'title' => 'Our Menu',
        'description' => 'Choose from our delicious options',
        'buttonText' => 'View Menu',
        'footerText' => 'Tap to select an item',
        'sections' => [
            [
                'title' => 'Main Dishes',
                'rows' => [
                    [
                        'title' => 'Burger',
                        'description' => 'Classic beef burger - $12.99',
                        'rowId' => 'burger',
                    ],
                    [
                        'title' => 'Pizza',
                        'description' => 'Margherita pizza - $14.99',
                        'rowId' => 'pizza',
                    ],
                ],
            ],
            [
                'title' => 'Drinks',
                'rows' => [
                    [
                        'title' => 'Soda',
                        'description' => 'Coca-Cola, Sprite, Fanta - $2.99',
                        'rowId' => 'soda',
                    ],
                    [
                        'title' => 'Coffee',
                        'description' => 'Fresh brewed coffee - $3.99',
                        'rowId' => 'coffee',
                    ],
                ],
            ],
        ],
    ]);

List Limits

  • Maximum 10 sections
  • Maximum 10 rows per section
  • Row title: max 24 characters
  • Row description: max 72 characters

Poll Messages

Single Choice Poll

$response = EvolutionApi::for('my-instance')
    ->messages()
    ->poll(
        number: '5511999999999',
        name: 'What is your favorite color?',
        values: ['Red', 'Blue', 'Green', 'Yellow'],
        selectableCount: 1
    );

Multiple Choice Poll

$response = EvolutionApi::for('my-instance')
    ->messages()
    ->poll(
        number: '5511999999999',
        name: 'Select your interests (up to 3)',
        values: [
            'Sports',
            'Music',
            'Movies',
            'Technology',
            'Travel',
            'Food',
        ],
        selectableCount: 3
    );

Using DTO

use Lynkbyte\EvolutionApi\DTOs\Message\SendPollMessageDto;

$response = EvolutionApi::for('my-instance')
    ->messages()
    ->sendPoll([
        'number' => '5511999999999',
        'name' => 'Rate our service',
        'values' => ['Excellent', 'Good', 'Average', 'Poor'],
        'selectableCount' => 1,
    ]);

Poll Limits

  • Maximum 12 options
  • Option text: max 100 characters
  • Poll question: max 256 characters

Template Messages

For WhatsApp Business API approved templates:

use Lynkbyte\EvolutionApi\DTOs\Message\SendTemplateMessageDto;

$response = EvolutionApi::for('my-instance')
    ->messages()
    ->sendTemplate([
        'number' => '5511999999999',
        'name' => 'order_confirmation',
        'language' => 'en',
        'components' => [
            [
                'type' => 'header',
                'parameters' => [
                    ['type' => 'image', 'image' => ['link' => 'https://example.com/logo.png']],
                ],
            ],
            [
                'type' => 'body',
                'parameters' => [
                    ['type' => 'text', 'text' => 'John'],
                    ['type' => 'text', 'text' => '#12345'],
                    ['type' => 'text', 'text' => '$99.99'],
                ],
            ],
            [
                'type' => 'button',
                'sub_type' => 'url',
                'index' => 0,
                'parameters' => [
                    ['type' => 'text', 'text' => '12345'],
                ],
            ],
        ],
    ]);

Handling Responses

Button and list selections come as webhook events:

use Lynkbyte\EvolutionApi\Webhooks\AbstractWebhookHandler;
use Lynkbyte\EvolutionApi\DTOs\WebhookPayloadDto;

class InteractiveResponseHandler extends AbstractWebhookHandler
{
    protected array $events = ['MESSAGES_UPSERT'];

    public function handle(WebhookPayloadDto $payload): void
    {
        $message = $payload->data['message'] ?? [];

        // Button response
        if (isset($message['buttonsResponseMessage'])) {
            $selectedId = $message['buttonsResponseMessage']['selectedButtonId'];
            $this->handleButtonResponse($payload->sender, $selectedId);
        }

        // List response
        if (isset($message['listResponseMessage'])) {
            $selectedId = $message['listResponseMessage']['singleSelectReply']['selectedRowId'];
            $this->handleListResponse($payload->sender, $selectedId);
        }

        // Poll vote
        if (isset($message['pollUpdateMessage'])) {
            $votes = $message['pollUpdateMessage']['vote'];
            $this->handlePollVote($payload->sender, $votes);
        }
    }

    private function handleButtonResponse(string $sender, string $buttonId): void
    {
        match ($buttonId) {
            'opt1' => $this->processOption1($sender),
            'opt2' => $this->processOption2($sender),
            'opt3' => $this->processOption3($sender),
            default => null,
        };
    }
}

Examples

Customer Service Menu

public function sendServiceMenu(string $phone): void
{
    EvolutionApi::for('my-instance')
        ->messages()
        ->sendList([
            'number' => $phone,
            'title' => 'Customer Service',
            'description' => 'How can we help you today?',
            'buttonText' => 'Get Help',
            'footerText' => 'Available 24/7',
            'sections' => [
                [
                    'title' => 'Orders',
                    'rows' => [
                        ['title' => 'Track Order', 'description' => 'Check your order status', 'rowId' => 'track_order'],
                        ['title' => 'Cancel Order', 'description' => 'Request cancellation', 'rowId' => 'cancel_order'],
                        ['title' => 'Return Item', 'description' => 'Start a return', 'rowId' => 'return_item'],
                    ],
                ],
                [
                    'title' => 'Account',
                    'rows' => [
                        ['title' => 'Update Info', 'description' => 'Change your details', 'rowId' => 'update_info'],
                        ['title' => 'Payment Methods', 'description' => 'Manage payments', 'rowId' => 'payments'],
                    ],
                ],
                [
                    'title' => 'Support',
                    'rows' => [
                        ['title' => 'Talk to Agent', 'description' => 'Connect with support', 'rowId' => 'agent'],
                        ['title' => 'FAQ', 'description' => 'Common questions', 'rowId' => 'faq'],
                    ],
                ],
            ],
        ]);
}

Confirmation Dialog

public function sendConfirmation(string $phone, string $action): void
{
    EvolutionApi::for('my-instance')
        ->messages()
        ->sendButtons(
            number: $phone,
            title: 'Confirm Action',
            description: "Are you sure you want to {$action}?",
            buttons: [
                ['buttonId' => 'confirm_yes', 'buttonText' => 'Yes, proceed'],
                ['buttonId' => 'confirm_no', 'buttonText' => 'No, cancel'],
            ],
            footer: 'This action cannot be undone'
        );
}

Feedback Survey

public function sendFeedbackSurvey(string $phone, string $orderId): void
{
    EvolutionApi::for('my-instance')
        ->messages()
        ->poll(
            number: $phone,
            name: "How would you rate your experience with order #{$orderId}?",
            values: [
                'Excellent - Very satisfied',
                'Good - Satisfied', 
                'Average - Neutral',
                'Poor - Unsatisfied',
                'Very Poor - Very unsatisfied',
            ],
            selectableCount: 1
        );
}

Next Steps