Skip to content

Все для WordPress, веб-розробки — і не тільки

🤖 Viber чат-бот на PHP: надсилання структурованих повідомлень з клавіатурним меню

🤖 Viber чат-бот на PHP: надсилання структурованих повідомлень з клавіатурним меню

Користувач натискає кнопку в чаті й отримує не голий текст, а сітку з картинок, посилань і кольорових клавіш. Виглядає як нативний застосунок. Насправді це звичайний JSON, який ваш PHP-скрипт віддає через Viber REST API.

Проблема більшості посібників: вони вчать відповідати текстом на текст. Реальний бізнес-бот повинен показувати клавіатурне меню з кнопками-посиланнями, картинки та каруселі. Інакше користувач просто не зрозуміє, що бот уміє, і піде. З лютого 2024 року Viber перевів створення ботів на комерційну основу, 100 € на місяць через офіційних партнерів Rakuten Viber, а автентифікація переходить у HTTP-заголовок X-Viber-Auth-Token, а не в тіло запиту. Сніпети з auth_token всередині JSON більше не працюють.

Тут, робочий Viber-бот на PHP з нуля: від встановлення вебхука до надсилання структурованого клавіатурного меню з кнопками reply та open-url. Код актуальний для версії API 7.3.

💡 Швидкий огляд:

  • Реєструємо комерційного бота через партнера Viber і отримуємо токен автентифікації
  • Налаштовуємо вебхук через set_webhook із заголовком X-Viber-Auth-Token
  • Приймаємо callback-події від Viber: webhook → subscribed → message
  • Формуємо клавіатурне меню, сітку кнопок із кастомними кольорами, розмірами та діями
  • Надсилаємо структуровану відповідь: текст, картинки, посилання, каруселі через send_message

Як влаштований Viber Bot API

Viber Bot API працює за REST-моделлю: ваш сервер отримує callback-запити на вебхук і відповідає викликами до https://chatapi.viber.com/pa/send_message. Кожен запит автентифікується токеном у заголовку X-Viber-Auth-Token.

Базовий цикл виглядає так:

  • Ви реєструєте бота через партнера Viber і отримуєте токен у панелі «Edit Info».
  • Налаштовуєте вебхук, URL вашого сервера з валідним SSL (Let's Encrypt підходить, він у довіреному списку Java-сертифікатів Viber; самопідписані не приймаються).
  • Viber надсилає POST-запити на цей URL за кожної події: користувач підписався, написав повідомлення, натиснув кнопку.
  • Ваш PHP-скрипт читає вхідний JSON, розбирає поле event і відповідає викликом send_message.

Перший крок для розуміння, подивитися на живого бота. Відкрийте Viber, у пошуку публічних акаунтів знайдіть бота будь-якого відомого бренду. Майже у кожного є чат-бот з меню. На скріншоті нижче, типовий результат пошуку публічного акаунта.

Пошук публічного акаунта у Viber

Після підписки ви потрапляєте в чат 1-на-1. Виглядає приблизно так: аватар, вітальне повідомлення, кнопка для старту діалогу.

Екран публічного чату Viber після підписки

Натисніть іконку повідомлення у правому верхньому куті та надішліть «Привіт». Якщо бот налаштований на клавіатурне меню, побачите відповідь із сіткою кнопок:

Клавіатурне меню з кнопками в чаті Viber

Це і є структуроване повідомлення. Кнопки бувають двох типів: reply повертають текст назад боту (натискання «Новини» або «Статті»), а open-url відкривають посилання в браузері. Тепер напишемо код, який таке віддає.

Крок 1: Отримуємо токен і налаштовуємо вебхук

Токен лежить у панелі адміністратора Viber: розділ Edit Info → поле App Key. Це рядок із літер і цифр, його ви підставляєте в кожен запит до API.

Вебхук встановлюється одним POST-запитом до https://chatapi.viber.com/pa/set_webhook. Тіло запиту, JSON з URL вашого обробника та списком подій, на які ви підписуєтеся. Заголовок, X-Viber-Auth-Token з вашим токеном.

Скрипт встановлення вебхука (збережіть як setup.php і запустіть один раз):

1<?php
2$token = 'ВАШ_X_VIBER_AUTH_TOKEN';
3
4$data = json_encode([
5 'url' => 'https://your-domain.com/webhook.php',
6 'event_types' => ['message', 'subscribed', 'conversation_started'],
7]);
8
9$ch = curl_init('https://chatapi.viber.com/pa/set_webhook');
10curl_setopt($ch, CURLOPT_POST, 1);
11curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
12curl_setopt($ch, CURLOPT_HTTPHEADER, [
13 'Content-Type: application/json',
14 'X-Viber-Auth-Token: ' . $token,
15]);
16curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
17
18$result = curl_exec($ch);
19$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
20curl_close($ch);
21
22echo "HTTP {$httpCode}: {$result}\n";
23
24if ($httpCode === 200) {
25 $response = json_decode($result, true);
26 if (($response['status'] ?? -1) === 0) {
27 echo "Вебхук установлен успешно.\n";
28 } else {
29 echo "Ошибка Viber: " . ($response['status_message'] ?? 'неизвестная') . "\n";
30 }
31}

Що тут відбувається: cURL надсилає POST на set_webhook. Токен, строго в заголовку, не в тілі. Viber повертає {"status":0} у разі успіху й одразу ж надсилає callback webhook на вказаний URL, перевіряючи його доступність. Відповідь {"status":0,"status_message":"ok"} на цей callback є обов'язковою (розберемо в наступному кроці).

Якщо отримуєте invalidUrl, перевірте SSL-сертифікат. Let's Encrypt працює, самопідписаний, ні. На своєму сервері достатньо виконати certbot --nginx -d your-domain.com і налаштувати автооновлення через cron.

Крок 2: Приймаємо callback-події від Viber

Коли користувач взаємодіє з ботом, Viber надсилає на ваш вебхук POST-запит із JSON. Ваше завдання, прочитати поле event і зреагувати.

Мінімальний обробник webhook.php, який коректно відповідає на всі події:

1<?php
2$request = file_get_contents("php://input");
3$input = json_decode($request, true);
4
5if ($input['event'] === 'webhook') {
6 $response = [
7 'status' => 0,
8 'status_message' => 'ok',
9 'event_types' => ['delivered', 'seen', 'message', 'subscribed', 'conversation_started'],
10 ];
11 echo json_encode($response);
12 exit;
13}
14
15if ($input['event'] === 'subscribed') {
16 $sender_id = $input['sender']['id'];
17 sendWelcomeMessage($sender_id);
18}
19
20if ($input['event'] === 'conversation_started') {
21 $sender_id = $input['sender']['id'];
22 sendMainMenu($sender_id);
23}
24
25if ($input['event'] === 'message') {
26 $type = $input['message']['type'];
27 $text = $input['message']['text'];
28 $sender_id = $input['sender']['id'];
29 $sender_name = $input['sender']['name'];
30
31 $data = match ($text) {
32 'News' => getNewsList($sender_id),
33 'Articles' => getArticleList($sender_id),
34 'Gallery' => getGalleryList($sender_id),
35 default => getMainMenu($sender_id),
36 };
37
38 sendToViber($data);
39}

Розбір подій:

  • webhook, надходить один раз під час встановлення вебхука. Обов’язково повернути {"status":0,"status_message":"ok"} із переліком підтримуваних подій. Без цього Viber не підтвердить URL, і бот не запуститься.
  • subscribed, користувач підписався на бота. Ідеальний момент для надсилання вітального меню.
  • conversation_started, користувач відкрив чат, уперше або повторно. Теж підходить для показу головного меню.
  • message, основна робоча подія. У text лежить або довільне повідомлення користувача, або ActionBody натиснутої кнопки (якщо її тип reply). Саме так бот розуміє, що обрали: «News», «Articles» чи «Gallery».

Конструкція match() доступна з PHP 8. Якщо у вас PHP 7.4, замініть на switch.

Крок 3: Формуємо клавіатурне меню

Клавіатура прикріплюється до будь-якого повідомлення через поле keyboard в JSON-об’єкті send_message. Це масив кнопок із роздільним налаштуванням ширини (Columns, 1-6), висоти (Rows, 1-2), кольору тла, тексту та дії.

Функція, що збирає головне меню із семи reply-кнопок та однієї кнопки-посилання:

1<?php
2
3function getMainMenu(string $user_id): array
4{
5 $buttons = [];
6
7 $addReplyButton = function (string $label, string $actionBody, int $cols = 2, int $rows = 2) use (&$buttons) {
8 $buttons[] = [
9 'Columns' => $cols,
10 'Rows' => $rows,
11 'Text' => $label,
12 'TextSize' => 'regular',
13 'TextVAlign' => 'bottom',
14 'TextHAlign' => 'center',
15 'TextOpacity' => 100,
16 'ActionType' => 'reply',
17 'ActionBody' => $actionBody,
18 'BgColor' => '#FFFFFF',
19 ];
20 };
21
22 $addReplyButton('NEWS', 'News');
23 $addReplyButton('ARTICLES', 'Articles');
24 $addReplyButton('INTERVIEWS', 'Interviews');
25 $addReplyButton('GALLERY', 'Gallery');
26 $addReplyButton('POLL', 'Poll');
27 $addReplyButton('PLAYER OF THE MONTH','POTM');
28 $addReplyButton('QUOTE OF THE DAY', 'Quote');
29
30 $buttons[] = [
31 'Columns' => 4,
32 'Rows' => 2,
33 'Text' => 'VISIT OUR WEBSITE',
34 'TextSize' => 'regular',
35 'TextVAlign' => 'bottom',
36 'TextHAlign' => 'center',
37 'TextOpacity' => 100,
38 'ActionType' => 'open-url',
39 'ActionBody' => 'https://your-site.com',
40 'BgColor' => '#FFFFFF',
41 ];
42
43 return [
44 'receiver' => $user_id,
45 'type' => 'text',
46 'text' => 'Please select one of the options below:',
47 'keyboard' => [
48 'Type' => 'keyboard',
49 'BgColor' => '#FFFFFF',
50 'Buttons' => $buttons,
51 ],
52 ];
53}

Кнопки з Columns=2 і Rows=2, квадратні, по три в ряд (2+2+2=6). Кнопка-посилання з Columns=4 займає окремий рядок. Сітка збирається зліва направо, згори донизу. Сума Columns у ряді визначає розкладку.

Параметри кнопки:

Параметр

Значення

Призначення

Columns

1-6

Ширина кнопки в умовних колонках

Rows

1-2

Висота кнопки в рядах

ActionType

reply або open-url

reply, повернути текст боту, open-url, відкрити браузер

ActionBody

рядок

Для reply, текст, який бот отримає назад; для open-url, URL

Text

рядок

Напис на кнопці, підтримує HTML-теги b, i та font color

BgColor

HEX

Колір тла кнопки

Image

URL

Зображення поверх кнопки, JPEG, опціонально

Крок 4: Надсилаємо дані через send_message

Функція-відправник, яку ви викликаєте з обробника подій:

1<?php
2
3function sendToViber(array $data): void
4{
5 $token = 'ВАШ_X_VIBER_AUTH_TOKEN';
6
7 $ch = curl_init('https://chatapi.viber.com/pa/send_message');
8 curl_setopt($ch, CURLOPT_POST, 1);
9 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
10 curl_setopt($ch, CURLOPT_HTTPHEADER, [
11 'Content-Type: application/json',
12 'X-Viber-Auth-Token: ' . $token,
13 ]);
14 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
15
16 $result = curl_exec($ch);
17 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
18 curl_close($ch);
19
20 if ($httpCode !== 200) {
21 error_log("Viber API error: HTTP {$httpCode} - {$result}");
22 }
23}

Ключова відмінність від старих посібників: токен у заголовку, а не в тілі JSON. У тілі лише поля receiver, type, text, keyboard та опціональні sender.name, sender.avatar, tracking_data. Максимальний розмір JSON: 30 КБ. Перевищили, і Viber мовчки відкидає повідомлення, перевіряйте strlen(json_encode($data)) перед надсиланням.

Крок 5: Збираємо контент для кнопок

Коли користувач натискає reply-кнопку, її ActionBody відлітає на вебхук як текст повідомлення. Ви парсите його в match() і викликаєте потрібну функцію. Ось приклад для списку новин із зображеннями:

1<?php
2
3function getNewsList(string $user_id): array
4{
5 $newsItems = [
6 [
7 'title' => 'Your Article Title',
8 'link' => 'https://your-site.com/article-1',
9 'image' => 'https://your-site.com/images/article-1.jpg',
10 ],
11 [
12 'title' => 'Another Article',
13 'link' => 'https://your-site.com/article-2',
14 'image' => 'https://your-site.com/images/article-2.jpg',
15 ],
16 ];
17
18 $buttons = [];
19 foreach ($newsItems as $item) {
20 $buttons[] = [
21 'Columns' => 2,
22 'Rows' => 2,
23 'ActionType' => 'open-url',
24 'ActionBody' => $item['link'],
25 'BgColor' => '#FFFFFF',
26 'Image' => $item['image'],
27 ];
28 $buttons[] = [
29 'Columns' => 4,
30 'Rows' => 2,
31 'Text' => $item['title'],
32 'TextSize' => 'regular',
33 'TextHAlign' => 'left',
34 'TextVAlign' => 'top',
35 'ActionType' => 'open-url',
36 'ActionBody' => $item['link'],
37 'BgColor' => '#F5F5F5',
38 ];
39 }
40
41 return [
42 'receiver' => $user_id,
43 'type' => 'text',
44 'text' => 'Here are the latest updates:',
45 'keyboard' => [
46 'Type' => 'keyboard',
47 'BgColor' => '#DDDDDD',
48 'Buttons' => $buttons,
49 ],
50 ];
51}

З боку користувача це виглядає як сітка карток: ліворуч зображення, праворуч заголовок. Натискання на будь-яку частину відкриває посилання в браузері.

Rich-повідомлення з картинками та посиланнями у Viber

Так само збираються галерея, список статей або опитування, змінюється лише вміст масиву $buttons і текст повідомлення. Якщо контенту багато і JSON наближається до 30 КБ, розбивайте на сторінки з кнопкою «Next».

Якщо вам зручніше працювати не з чистим API, а з готовою PHP-бібліотекою, подивіться viber-bot-php від Bogdaan, вона бере на себе валідацію підпису, роутинг подій і формування JSON.

Коротко: повний порядок запуску

  • Отримайте токен у панелі Viber Admin Panel: розділ Edit Info → App Key.
  • Викладіть обробник на сервер з HTTPS. Let's Encrypt підходить, самопідписаний сертифікат, ні. Viber звіряє сертифікат із довіреним списком Java Root CA.
  • Встановіть вебхук POST-запитом до https://chatapi.viber.com/pa/set_webhook з тілом {"url":"https://ваш-домен/webhook.php","event_types":[...]} та заголовком X-Viber-Auth-Token.
  • Перевірте відповідь: {"status":0}, успіх. Viber одразу надішле callback webhook на вашу URL. Переконайтеся, що скрипт повертає {"status":0,"status_message":"ok"}.
  • Надішліть перше меню: при події conversation_started викличте getMainMenu() і передайте результат у sendToViber().

⁉️🤔 Часті запитання

Чи можна використовувати самопідписаний SSL-сертифікат для вебхука?

Ні. Viber перевіряє сертифікат за списком довірених кореневих центрів сертифікації Java. Самопідписаний сертифікат спричиняє помилку invalidUrl під час встановлення вебхука. Let's Encrypt у цьому списку є і він безплатний. На своєму сервері виконайте certbot --nginx -d your-domain.com, додайте автооновлення в cron, і Viber прийме сертифікат без проблем.

Чим відрізняється reply від open-url в ActionType?

reply надсилає ActionBody назад на вебхук як текст повідомлення. PHP-скрипт бачить його в $input['message']['text'] і маршрутизує через match(). Використовуйте для навігації всередині бота. open-url відкриває посилання у зовнішньому браузері, вебхук при цьому не смикається. На практиці меню комбінує обидва типи: 5-6 reply-кнопок для розділів і одну широку open-url-кнопку для переходу на сайт.

Які типи повідомлень підтримує Viber Bot API?

Viber Bot API підтримує дев'ять типів поля type у send_message: text (звичайний текст), picture (JPEG-зображення), video (відеофайл), file (будь-який файл до 50 МБ), location (геоточка), contact (візитівка), sticker (стікер), rich_media (карусель карток) і url (прев'ю посилання). Актуальний список з обов'язковими полями дивіться в документації Viber Developers Hub. Найпоширеніший сценарій: text + keyboard для меню та picture для надсилання зображень. Каруселі гарні для вітрин і каталогів, але потребують більше коду.

Що робити, якщо користувач не бачить клавіатуру?

Три часті причини. Перша: JSON з клавіатурою перевищив 30 КБ, Viber мовчки відкидає такі повідомлення. Перевіряйте strlen(json_encode($data)) перед надсиланням. Друга: у відповіді на set_webhook не було "status":0, вебхук не встановлено, бот не отримує повідомлення. Третя: використовується старий формат з auth_token у тілі JSON. З API 7.0 це ігнорується, потрібен заголовок X-Viber-Auth-Token. Для налагодження увімкніть логування відповіді Viber API: він повертає читабельний JSON з кодом помилки invalidAuthToken, badData або missingData.

Чи можна змінити клавіатуру після надсилання?

Так. З кожним новим повідомленням можна надіслати іншу клавіатуру. Клієнт Viber завжди показує останню отриману. Це дозволяє будувати багаторівневі меню: головне меню → підменю розділу → конкретний контент. Кожен рівень зі своїм набором кнопок, і користувач переміщується між ними натисканнями reply-клавіш.

Скільки коштує запуск Viber-бота у 2026 році?

З 5 лютого 2024 року створення нового бота, 100 € на місяць через офіційних партнерів Rakuten Viber. Боти, створені до цієї дати, працюють за старими умовами. У вартість входить виділений акаунт із панеллю адміністратора, аналітика та доступ до всіх типів повідомлень, включно з rich_media і Viber Pay. Технічна частина API для комерційних і старих безплатних ботів ідентична.

Бот готовий: що далі

Клавіатурне меню — це лише вхідна точка. Коли базова механіка відпрацьована, додавайте каруселі контенту через rich_media, платежі через Viber Pay і сегментацію користувачів за тим, які кнопки вони натискають найчастіше. Кожен новий рівень не змінює основу: ви так само читаєте event, так само шлете send_message із заголовком X-Viber-Auth-Token.

Якщо потрібен живий приклад робочого коду, подивіться репозиторій viber-bot-php на GitHub, там розібрані всі події, підпис запитів і формування клавіатури з картинками. А для візуального старту ось півгодинний туторіал зі створення Viber-бота з нуля:

Головне, що варто запам'ятати: Viber Bot API простий на старті, але вимогливий до деталей. Правильний заголовок автентифікації, довірений SSL, валідний JSON до 30 КБ і чітка маршрутизація ActionBody, цього достатньо, щоб бот працював без збоїв. Беріть сніпети вище, підставляйте свій токен і домен, і запускайте перше меню сьогодні.