SDK Viber Bot REST API для Laravel: типізовані DTO, перевірка підпису вебхуків і надсилання повідомлень. Viber залишається одним із основних месенджерів для комунікації з клієнтами в Україні.
Теги
README
Viber Bot API
Viber Bot REST API SDK for Laravel — a typed HTTP client, webhook signature verification, and a nutgram-style inbound handler engine.
It is the reusable Viber engine (think nutgram/nutgram + its Laravel bridge):
the package owns the protocol, while app-specific glue (persistence, CRM binding,
notification channels) lives in your application.
Features
- Outbound client —
Account,Messages,Usersover a typed transport with timeout/retry and per-call token override (multi-account). - Message builders — text, picture, video, file, contact, location, url,
sticker, and rich-media (carousel), each self-validating its Viber constraints
and carrying the common
tracking_data/min_api_versionparameters. - Keyboards — fluent
Button/Keyboardbuilders (full Viber field set: background media, text styling, open-url behaviour, Frame / MediaPlayer / Map / InternalBrowser) and aSharePhoneButtononboarding primitive. - Webhook security —
X-Viber-Content-SignatureHMAC-SHA256 verification as route middleware. - Typed inbound events — every callback hydrated into a
spatie/laravel-dataDTO (MessageEvent,SubscribedEvent,ConversationStartedEvent, …). - Handler engine — register
onMessage/onText/onContact/ … handlers with a short-circuitable middleware pipeline; dispatched automatically from the webhook controller. - Artisan commands — manage the webhook lifecycle from the CLI.
Requirements
- PHP 8.2 – 8.5
- Laravel 11, 12, or 13
Installation
The package is distributed via a private Composer registry. Add the repository, then require it:
// composer.json
"repositories": [
{ "type": "composer", "url": "https://repo.xitedev.com" }
]
composer require sashalenz/viber-bot-api
Publish the config:
php artisan vendor:publish --tag="viber-bot-api-config"
Set at least the token and sender name in your .env:
VIBER_BOT_TOKEN=your-public-account-token
VIBER_BOT_SENDER_NAME=A20
Configuration
All options live in config/viber-bot-api.php and are env-driven:
| Env var | Default | Purpose |
|---|---|---|
VIBER_BOT_TOKEN |
— | Public-account auth token (X-Viber-Auth-Token). |
VIBER_BOT_API_URL |
https://chatapi.viber.com/pa/ |
API base URL. |
VIBER_BOT_SENDER_NAME |
Bot |
Sender name (Viber caps it at 28 chars). |
VIBER_BOT_SENDER_AVATAR |
— | Sender avatar URL. |
VIBER_BOT_WEBHOOK_ROUTES_ENABLED |
true |
Register the webhook route. |
VIBER_BOT_WEBHOOK_PREFIX |
viber-bot-api |
Route path prefix. |
VIBER_BOT_WEBHOOK_KEY |
webhook |
Route path segment. |
VIBER_BOT_WEBHOOK_DOMAIN |
— | Optional route domain. |
VIBER_BOT_WEBHOOK_MIDDLEWARE |
— | Extra middleware (comma-separated). |
VIBER_BOT_VERIFY_SIGNATURE |
true |
Enforce the HMAC signature check. |
event_types (the events requested on set_webhook) is an array in the config
file and defaults to all of message, subscribed, unsubscribed,
conversation_started, delivered, seen, failed.
Outbound
use Sashalenz\ViberBotApi\ViberBotApi;
use Sashalenz\ViberBotApi\Messages\TextMessage;
ViberBotApi::messages()->send($viberUserId, new TextMessage('Привіт 👋'));
// per-call token override (multi-account: e.g. dev vs prod bot)
ViberBotApi::messages()->token($prodToken)->send($id, new TextMessage('…'));
// broadcast to up to 300 receivers per call
ViberBotApi::messages()->broadcast([$id1, $id2], new TextMessage('…'));
send() / broadcast() return a typed SendMessageResponse (->status,
->message_token, …). A non-zero Viber status throws ViberBotApiException.
Message builders
Every builder implements MessageContract and validates its own Viber
constraints in the constructor (throwing ViberBotApiException). Media is
URL-based — pass a public https:// URL, not a binary upload.
use Sashalenz\ViberBotApi\Messages\{
TextMessage, PictureMessage, VideoMessage, FileMessage, ContactMessage,
LocationMessage, UrlMessage, StickerMessage, RichMediaMessage,
};
use Sashalenz\ViberBotApi\Keyboards\Button;
new TextMessage('Hello'); // ≤ 7000 chars
new PictureMessage('https://cdn/p.jpg', text: 'caption'); // caption ≤ 768
new VideoMessage('https://cdn/v.mp4', size: 1_200_000); // ≤ 26 MB
new FileMessage('https://cdn/d.pdf', size: 50_000, fileName: 'invoice.pdf'); // ≤ 50 MB
new ContactMessage('Itamar', '+972511123123');
new LocationMessage(50.4501, 30.5234);
new UrlMessage('https://example.com');
new StickerMessage(40_100);
new RichMediaMessage(buttons: [Button::make()->text('Buy')->actionBody('buy')]);
Every builder also accepts the two send_message parameters common to all
message types — trackingData (≤ 4096 chars, echoed back on the matching
delivered / seen / message callbacks) and minApiVersion:
new TextMessage('Hello', trackingData: 'order-42', minApiVersion: 7);
new StickerMessage(40_100, trackingData: 'sticker-ctx');
Keyboards
use Sashalenz\ViberBotApi\Keyboards\{Keyboard, Button, SharePhoneButton};
$keyboard = Keyboard::make()
->button(Button::make()->text('Yes')->actionType('reply')->actionBody('yes'))
->button(Button::make()->text('No')->actionType('reply')->actionBody('no'))
->toArray();
ViberBotApi::messages()->send($id, new TextMessage('Confirm?', $keyboard));
// the full documented field set is supported on both builders:
Keyboard::make()
->customDefaultHeight(50)->heightScale(80)
->buttonsGroup(columns: 6, rows: 2)
->inputFieldState('hidden')
->button(
Button::make()
->text('Open')->actionType('open-url')->actionBody('https://example.com')
->openUrl(type: 'internal', mediaType: 'not-media')
->textSize('large')->textAlign('center', 'middle')->textOpacity(80)
->bgMedia('https://cdn/bg.gif', type: 'gif', scaleType: 'fill', loop: false)
->image('https://cdn/i.png', scaleType: 'crop')
->frame(borderWidth: 2, borderColor: '#000000', cornerRadius: 10)
);
// onboarding: ask the user to share their phone (binds a Viber id to a CRM record)
ViberBotApi::messages()->send(
$id,
new TextMessage('Share your number', (new SharePhoneButton)->toArray()),
);
Account / webhook
$info = ViberBotApi::account()->info(); // read-only — safe on a live bot
$info->webhook; // current webhook url
$info->subscribers_count;
ViberBotApi::account()->setWebhook('https://example.com/viber-bot-api/webhook');
ViberBotApi::account()->removeWebhook(); // rollback
⚠️ A Viber bot has exactly one webhook.
setWebhookoverwrites the previous one — there is no parallel delivery.
Users
$details = ViberBotApi::users()->details($viberUserId); // cache: max 2 calls/12h per user
$details->user; // id, name, avatar, country, …
ViberBotApi::users()->online([$id1, $id2]); // ≤ 100 ids per call
Inbound
The package registers POST /{prefix}/{webhook_key} (default
/viber-bot-api/webhook), guarded by the VerifyViberSignature middleware
(HMAC-SHA256 of the raw body against your token). Prefix, domain, extra
middleware, and on/off are configurable. The controller verifies the signature,
parses the payload into a typed event, dispatches it through the
container-bound Bot\Viber engine, and always responds 200 fast (Viber
retries any non-200).
Registering handlers
Bot\Viber is bound as a singleton, so register handlers once — e.g. in a
service provider's boot():
use Closure;
use Sashalenz\ViberBotApi\Bot\Viber;
use Sashalenz\ViberBotApi\Dto\Events\MessageEvent;
use Sashalenz\ViberBotApi\Dto\Update;
use Sashalenz\ViberBotApi\Messages\TextMessage;
$bot = app(Viber::class);
// middleware runs before/after, in registration order, and can short-circuit
$bot->middleware(fn (Update $update, Closure $next) => $next($update));
$bot->onText('/start', fn (MessageEvent $e, Viber $bot) => $bot->reply(new TextMessage('Hi!')));
$bot->onContact(fn (MessageEvent $e) => logger()->info('phone', [$e->message->contact?->phone_number]));
$bot->onMessage(fn (MessageEvent $e, Viber $bot) => $bot->reply(new TextMessage('echo: '.$e->message->text)));
$bot->onSubscribed(fn ($e) => /* … */ null);
$bot->onDelivered(fn ($e) => /* … */ null); // also onSeen / onFailed / onUnsubscribed
The first matching handler (in registration order) wins. Handlers receive the
typed event plus the bot instance; $bot->reply(...) sends a send_message back
to the user behind the current update. onText($pattern, ...) matches the
message text against an anchored unicode regex.
conversation_started
This event is special: the user is not subscribed yet, so a real
send_message is rejected. Return a MessageContract (or payload array) from
the handler and the controller emits it inline in the HTTP 200 response, wrapped
with the sender envelope:
$bot->onConversationStarted(fn ($e) => new TextMessage('Welcome 👋'));
Console commands
php artisan viber:get-account-info # read-only PA snapshot
php artisan viber:set-webhook {url?} --force # register webhook (destructive — overwrites)
php artisan viber:delete-webhook --force # detach webhook (rollback)
set-webhook defaults to the package webhook route URL when no argument is
given, and prompts for confirmation unless --force is passed.
Typed request DTOs (optional)
If you prefer typed request payloads over the array/builder surface, use the
RequestData DTOs:
use Sashalenz\ViberBotApi\RequestData\{SendMessageData, SetWebhookData};
use Sashalenz\ViberBotApi\Messages\TextMessage;
ViberBotApi::messages()->sendData(new SendMessageData(
receiver: $viberUserId,
message: new TextMessage('Привіт'),
trackingData: 'order-42',
));
ViberBotApi::account()->setWebhookData(new SetWebhookData(
url: 'https://example.com/viber-bot-api/webhook', // must be HTTPS
eventTypes: ['message', 'conversation_started'],
));
Testing
composer test # Pest
composer analyse # PHPStan (level 6)
composer format # Pint
Viber gotchas baked into the design
- User ids are opaque strings, not numbers.
conversation_started: the user is not yet subscribed — you can only greet by returning asend_message-shaped body in the HTTP response (within 5 min).- Media is URL-based (not binary uploads).
get_user_detailsis capped at 2 calls / 12h per user — cache it.- Commercial: customer-initiated session messages (24h window) are free; business-initiated messages are paid.
License
MIT. See LICENSE.md.
Схожі пакети
SendPulse REST API
Офіційний PHP SDK для SendPulse: email-розсилки, SMS, web-push, чат-боти та транзакційна пошта. Сервіс заснований в Україні і виріс у міжнародну платформу, тож SDK підтримується активно і має найбільшу аудиторію в добірці.
NovaPoshta for Laravel
Обгортка над API 2.0 Нової Пошти для Laravel: адреси, відділення, вантажі, документи та відстеження посилок. Один із найпоширеніших пакетів для інтеграції з Новою Поштою в українських проєктах.
TurboSMS for Laravel
Пакет для роботи з TurboSMS у Laravel: надсилання SMS і Viber, перевірка балансу та статусів доставки. Один із найпоширеніших SMS-пакетів в українських Laravel-проєктах.
Теги
- Версія
- 1.0.0
- Laravel
- 13
- Завантажень
- 294
- Реліз
- 21 червня 2026
- Походження
- Українська розробка
- Категорія
- Українські сервіси