sashalenz/viber-bot-api
Composer 安装命令:
composer require sashalenz/viber-bot-api
包简介
Viber Bot REST API SDK for Laravel — client, typed DTOs, webhook signature verification and a nutgram-style handler engine.
README 文档
README
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.
- Keyboards — fluent
Button/Keyboardbuilders 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')]);
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)); // 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.
统计信息
- 总下载量: 1
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-17