Appearance
Reference
Helpers
All helpers are defined in src/helpers.php and available globally when the package is installed.
Context & Buses
| Helper | Returns | Description |
|---|---|---|
wHook() | Webhook | Current request context (api, update, bot, user) |
telegramApi($token, $baseUrl?) | Api | Create a Telegram API client |
replyKeyBus() | ReplyKeyBus | Reply keyboard handler registry |
callbackQueryBus() | CallbackQueryBus | Inline callback handler registry |
stateAnswerBus() | StateAnswerBus | Text input handler registry |
inlineQueryBus() | InlineQueryBus | Inline-mode query handler registry |
commandBus() | CommandBus | /command handler registry — see Commands |
botEventBus() | BotEventBus | Lifecycle event registry — see Events & Listeners |
stateData() | StateDataService | StateData create/merge service |
botUserStatus() | BotUserStatus | Bot-user reachability tracker — see Architecture |
navState() | NavState | Per-message navigation state (page/sort/filter) that outgrows callback_data |
exceptionHandler() | ExceptionHandler | Webhook exception handler |
Encoding
| Helper | Description |
|---|---|
encodeCallback($type, $method, $params = []) | Encode inline button callback_data (64-byte limit) |
decodeCallback($input) | Decode callback_data → ['type', 'method', 'params'] |
encodeAnswerState($type, $method, $params = []) | Encode user state string |
decodeAnswerState($input) | Decode user state → ['type', 'method', 'params'] |
Registration
| Helper | Description |
|---|---|
loadCallbackQueries($path) | Scan directory and register CallbackQuery subclasses |
loadStateAnswers($path) | Scan directory and register StateAnswer subclasses |
loadReplyKeys($path) | Scan directory and register ReplyKey subclasses |
loadCommands($path) | Scan directory and register Command subclasses |
loadInlineQueries($path) | Scan directory and register InlineQuery subclasses |
addUserReplyKeys(array $rows) | Register reply keys from config keyboard array |
resolveNamespace($path) | Resolve PSR-4 namespace from filesystem path |
Since v0.12.0 these run once per worker boot from TelegramBotServiceProvider (app classes in a booted() callback so they win collisions), not per request.
UI Helpers
| Helper | Description |
|---|---|
inlineSorter($buttons, $step?) | Arrange inline buttons into rows |
smartInlineKeysSorter($buttons, $step?, $limit?) | Sort by text length with row width limit |
addInlineKeysSorted($keyboard, $keys, $step?) | Add sorted rows to a Keyboard |
addInlineKeysSmartSorted($keyboard, $keys, $step?, $limit?) | Smart-sorted rows |
getInputInlineKeyText() | Get text of the pressed inline button |
inlineConfirmationKey($text, $target, $back, $confirmText?) | Create a confirmation button |
Access & Guards
| Helper | Description |
|---|---|
hasAccess(?int $power) | Check user role against required power level |
dependsOn(?bool $condition, ?string $message) | Throw FeatureIsDisabled if condition is falsy |
Debugging
| Helper | Description |
|---|---|
exceptionReport(Throwable $e) | Log + send trace/update to bug report chat |
debugMessage(string $message) | Log + send debug text to bug report chat |
mixedDebugMessage(mixed $data) | Log + send JSON-encoded data |
adminAlert(string $key, Closure|string $text, ?Bot $bot, ?int $throttle) | Tell the bot's owner and admins about something only they can fix, throttled per key (Logging) |
Configuration
Published to config/tbe-essence.php via php artisan tbe:install.
php
return [
// Reply keyboard layout per role
'keyboard' => [
'admin' => [[AdminPanelKey::class], ...],
'member' => [[MainMenuKey::class], ...],
],
// Commands registered on Telegram's own command menu via tbe:set-webhook
'commands' => [
HelpCommand::class,
],
// Bot management API token
'bot_access' => [
'token' => env('BOT_MANAGEMENT_ACCESS_TOKEN'),
],
// Single-bot mode defaults
'main' => [
'unique_id' => env('MAIN_UNIQUE_ID', 'main'),
'telegram_bot_token' => env('MAIN_TELEGRAM_BOT_TOKEN'),
'admin_chat_id' => env('MAIN_ADMIN_CHAT_ID'),
'currency' => env('MAIN_CURRENCY', 'USD'),
],
// Telegram API base URL
'base_bot_url' => env('TELEGRAM_BOT_BASE_URL', 'https://api.telegram.org/bot'),
// Error reporting destination
'bug_report' => [
'telegram_chat_id' => env('BUG_REPORT_TELEGRAM_CHAT_ID'),
],
// Log channels + Telegram notification for tbeLog()
'logging' => [
'channel' => env('TBE_LOG_CHANNEL'),
'channels' => [], // per-package overrides
'audit_channel' => env('TBE_LOG_AUDIT_CHANNEL'),
'telegram_notify' => env('TBE_LOG_TELEGRAM_NOTIFY', true),
],
// adminAlert() throttle window, seconds
'admin_alerts' => [
'throttle' => env('TBE_ADMIN_ALERT_THROTTLE', 21600),
],
// Developer override for hasAccess()
'developer' => [
'peer_id' => env('DEVELOPER_PEER_ID'),
],
// translations:stats / translations:check command config
'translation_stats' => [
'base_locale' => 'en',
'cache_key' => 'tbe.translation_stats',
'ttl' => 86400,
],
// Retention windows for model:prune (StateData, InlineConfirmation,
// MessageMeta). essence schedules `model:prune` hourly for all three in
// routes/console.php — no host-app scheduler setup needed.
'pruning' => [
'state_data_days' => env('TBE_PRUNE_STATE_DATA_DAYS', 7),
'message_metas_days' => env('TBE_PRUNE_MESSAGE_METAS_DAYS', 7),
'inline_confirmations_hours' => env('TBE_PRUNE_INLINE_CONFIRMATIONS_HOURS', 6),
],
// Opt out of essence's own routes, or move them off the default prefixes
'routes' => [
'enabled' => env('TBE_ROUTES_ENABLED', true),
'api_prefix' => env('TBE_ROUTES_API_PREFIX', 'api'),
'web_prefix' => env('TBE_ROUTES_WEB_PREFIX', ''),
],
// update_id dedup claim TTL — needs an atomic cache driver (redis/memcached),
// not array/file
'update_dedup' => [
'ttl_seconds' => env('TBE_UPDATE_DEDUP_TTL_SECONDS', 300),
],
];telegram.php
Merged from the package but typically overridden by the host app. Configures the telegram-bot-sdk BotsManager and HTTP client handler (LaravelHttpClient).
Database
Tables
| Table | Model | Description |
|---|---|---|
bots | Bot | Bot tenant (token, owner, activation) |
telegram_users | TelegramUser | Global Telegram user profiles |
bot_users | BotUser | Per-bot user (power, state, menu) |
message_metas | MessageMeta | Tracked messages for lock/revert |
state_data | StateData | JSON payload storage |
inline_confirmations | InlineConfirmation | Confirmation dialog state |
bot_users columns
| Column | Type | Description |
|---|---|---|
bot_id | FK | Tenant bot |
telegram_user_peer_id | FK | Telegram user |
power | int | Role level (see Roles enum) |
state | string, nullable | Encoded active input flow |
menu | enum | main or admin — controls keyboard |
status | string | active / blocked / unreachable — reachability, added in v0.12.0 (see Architecture) |
suspended_at | timestamp | Suspension flag |
last_interaction | timestamp | Last activity |
telegram_users.deactivated_at (nullable timestamp) holds the fourth, peer-global reachability state — the Telegram account itself is gone.
state_data columns
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
data | json, nullable | Arbitrary payload |
created_at / updated_at | timestamp | Added in v0.12.0 so model:prune can age rows out |
BotUser methods
php
$botUser->changeState(?string $state); // set or clear active state
$botUser->addParamToState(array $params); // merge params into current state
$botUser->getKeyboard(); // build reply keyboard for current context
$botUser->interact(); // update last_interaction timestamp
$botUser->reachability(); // 'active' | 'blocked' | 'unreachable' | 'deactivated'
$botUser->isReachable(); // bool — reachability() === 'active'
BotUser::reachable(); // scope: status 'active' AND not deactivated
BotUser::withStatus($s); // scope: whereIn('status', (array) $s)
BotUser::deactivated(); // scope: telegram account gone
BotUser::notSuspended(); // scope: suspended_at is nullStateDataService methods
php
stateData()->store(array $data = []): StateData;
stateData()->addData(StateData $row, array $data): void;Artisan Commands
| Command | Description |
|---|---|
tbe:install | Publish config and translations |
tbe:publish [--force] | (Re)publish package files |
tbe:singlebot:init [--force] | Create bot from tbe-essence.main config (--force reinitializes an existing bot) |
tbe:set-webhook [--unique-id=] [--endpoint=] [--all] | Set Telegram webhook + rotate secret token; --all rotates every bot |
tbe:bot-management-token | Generate bot management API token |
translations:stats [--base=] [--no-cache] | Report translation-key coverage per locale |
translations:check [--base=] | List translation keys missing from non-base locales |
tbe:make:callback-query {name} [--admin] [--all] [-f|-r|-s] | Generate CallbackQuery class (+ siblings) |
tbe:make:state-answer {name} [--admin] [--all] [-f|-c|-r] | Generate StateAnswer class (+ siblings) |
tbe:make:reply-key {name} [--admin] [--all] [-f|-c|-s] | Generate ReplyKey class (+ siblings) |
tbe:make:feature {name} [--admin] [--all] [-c|-r|-s] | Generate Feature class (+ siblings) |
tbe:make:inline-query {name} | Generate InlineQuery class |
tbe:make:command {name} [--admin] [--command-name=] [-d|--description=] | Generate Telegram Command class — see Commands |
tbe:set-webhook options
bash
php artisan tbe:set-webhook --unique-id=main
php artisan tbe:set-webhook --endpoint="/api/{unique_id}/telegram/bot/webhook"
php artisan tbe:set-webhook --allGenerates a new secret_token, hashes it on the bot record, and registers the webhook URL with Telegram. It also (re)builds each bot's Telegram command menu from config('tbe-essence.commands') — resolving each bot's locale through ResolvesBotLocale first, so the menu is translated per bot rather than in whatever locale the console process happens to be in.
Enums
Roles (src/Enums/Roles.php)
php
Roles::ADMIN->value // 100
Roles::MODERATOR->value // 10
Roles::MEMBER->value // 0AllowableFields (src/Enums/AllowableFields.php)
Used in StateAnswer $allowedFields:
php
AllowableFields::TEXT->value // 'text'
AllowableFields::PHOTO->value // 'photo'
AllowableFields::DOCUMENT->value // 'document'Routes
Defined in routes/api.php:
| Method | Path | Handler |
|---|---|---|
| GET/POST/PUT/PATCH/DELETE | /api/bots | Bot CRUD (management API) |
| GET | /api/{bot}/telegram/bot/webhook | Health check |
| POST | /api/{bot}/telegram/bot/webhook | Webhook handler |
Webhook POST requires header X-Telegram-Bot-Api-Secret-Token matching the bot's stored secret.
TelegramResponse API
php
$response = new TelegramResponse(
text: 'Hello',
replyMarkup: $keyboard,
parseMode: 'HTML',
);
$response->answer('Done!'); // callback toast text
$response->softAnswer('Saved'); // silent callback answer
$response->photo($inputFile); // send as photo with caption
$response->messageMetaModel($model); // attach MessageMeta on send
$response->send($chatId); // new message
$response->update($chatId, $messageId); // edit existing messageWhen called from a CallbackQuery handler without arguments, update() edits the message that contained the pressed button.
Webhook Context Export (for Jobs)
php
$context = wHook()->exportContext();
// In job:
wHook()->importContext($context);
wHook()->api()->sendMessage([...]);Useful for sending Telegram messages from queued jobs while preserving bot/user context.