Telegram Integration
Connect Botovis to Telegram and let users query your database through a Telegram bot
The Telegram package adds a Telegram bot adapter to Botovis, allowing users to interact with your database through Telegram messages. It supports full agent capabilities including streaming, write confirmations, and conversation context.
Installation
Install the package
composer require botovis/botovis-telegramPublish the configuration
php artisan vendor:publish --tag=botovis-telegram-configThis creates config/botovis-telegram.php.
Run the migration
php artisan vendor:publish --tag=botovis-telegram-migrations
php artisan migrateThis adds a telegram_chat_id column to your existing users table, enabling the link between Telegram accounts and your application users.
Create a Telegram bot
- Open Telegram and message @BotFather
- Send
/newbotand follow the prompts - Copy the bot token (looks like
7234567890:AAH...)
Configure environment variables
Add the bot token and enable the integration in your .env file:
BOTOVIS_TELEGRAM_ENABLED=true
BOTOVIS_TELEGRAM_BOT_TOKEN=7234567890:AAHxxxxxxxxxxxxxxxxxxxxxxxxx
BOTOVIS_TELEGRAM_WEBHOOK_SECRET=your-random-secret-stringSet up the webhook
php artisan botovis:telegram-setup --url=https://your-app.com/botovis/telegram/webhookConfiguration
The configuration file config/botovis-telegram.php:
return [
// Enable or disable the Telegram bot (webhook returns 404 when disabled)
'enabled' => env('BOTOVIS_TELEGRAM_ENABLED', false),
// Bot token from @BotFather
'bot_token' => env('BOTOVIS_TELEGRAM_BOT_TOKEN'),
// Secret token to verify incoming webhook requests from Telegram
// Sent in the X-Telegram-Bot-Api-Secret-Token header
'webhook_secret' => env('BOTOVIS_TELEGRAM_WEBHOOK_SECRET'),
// How long (in seconds) a /connect code remains valid
'connect_code_ttl' => 300, // 5 minutes
// Message shown to users who haven't linked their Telegram account
'guest_message' => env(
'BOTOVIS_TELEGRAM_GUEST_MESSAGE',
'Please link your Telegram account first...'
),
// Show intermediate reasoning steps as separate messages
'show_steps' => env('BOTOVIS_TELEGRAM_SHOW_STEPS', false),
// Route configuration
'route' => [
'prefix' => 'botovis/telegram',
'middleware' => [], // No auth middleware — Telegram sends webhooks
],
];User Linking (Connect System)
Telegram users must link their Telegram account to your application user account. Botovis uses a secure code-based system:
How It Works
- The user visits the Botovis panel in your web app and clicks "Connect Telegram"
- The panel generates a one-time connect code (valid for 5 minutes by default)
- The user opens Telegram and sends
/connect CODEto your bot - The bot verifies the code and links the Telegram chat ID to the application user
- From now on, the user can chat with the bot directly
The connect code TTL is configurable:
'connect_code_ttl' => 300, // 5 minutes (default)Disconnect
Users can unlink their Telegram account through the panel. The panel API calls the disconnect() endpoint, which removes the telegram_chat_id from the user record.
Guest Users
If an unlinked Telegram user messages the bot, they receive the guest_message:
'guest_message' => env(
'BOTOVIS_TELEGRAM_GUEST_MESSAGE',
'Please link your Telegram account first. Go to your app panel and use the "Connect Telegram" option.'
),How It Works
Telegram User → Message → Telegram API → Webhook → WebhookController
│
TelegramAdapter
│
AgentOrchestrator
│
stream() generator loop
│
TelegramFormatter
│
Telegram API (sendMessage)
│
Telegram UserMessage Flow
- User sends a message to the bot on Telegram
- Telegram sends a webhook POST to your Laravel app at
/{prefix}/webhook - The
WebhookControllerreceives the update and passes it toTelegramAdapter - The adapter looks up the user by
telegram_chat_idand checks permissions - During processing, a typing indicator is shown (refreshed every 4 seconds)
- The agent's final response is formatted to HTML and sent back via the Telegram API
- If a write confirmation is needed, inline keyboard buttons are shown
Typing Indicator
The adapter uses Botovis's streaming API internally. While the agent is reasoning and calling tools, the bot continuously sends a "typing..." indicator so the user knows it's working.
Write Confirmations
When the agent needs to perform a write operation, the bot sends a message with inline keyboard buttons:
🔧 The agent wants to create a record:
Table: products
Name: New Widget
Price: $29.99
[✅ Confirm] [❌ Reject]The user taps a button, and the bot handles the confirmation or rejection accordingly.
Formatting
Telegram messages are formatted using HTML parse mode:
- Bold text for emphasis
Codeformatting for technical values- Structured layouts for data tables and confirmations
- Markdown from the agent is converted to Telegram-compatible HTML
Webhook Management
Use the botovis:telegram-setup command to manage your webhook:
# Set webhook
php artisan botovis:telegram-setup --url=https://your-app.com/botovis/telegram/webhook
# Check webhook info
php artisan botovis:telegram-setup --info
# Remove webhook
php artisan botovis:telegram-setup --removeLocal Development
For local development with Telegram webhooks:
- Install ngrok:
brew install ngrok - Start your Laravel dev server:
php artisan serve - Start ngrok:
ngrok http 8000 - Copy the HTTPS URL (e.g.,
https://abc123.ngrok.io) - Set the webhook:
php artisan botovis:telegram-setup --url=https://abc123.ngrok.io/botovis/telegram/webhookngrok URL changes
Free ngrok URLs change every time you restart ngrok. Remember to re-run the webhook setup command when the URL changes.
Security Considerations
- Bot token — Keep your bot token secret. Never commit it to version control.
- Webhook secret — Set
BOTOVIS_TELEGRAM_WEBHOOK_SECRETto verify incoming requests from Telegram. The secret is sent in theX-Telegram-Bot-Api-Secret-Tokenheader. - Connect system — Only users who have linked their account via the secure connect code flow can use the bot.
- Role-based access — Linked Telegram users inherit the same role-based permission system as web users.
- Write confirmation — All write operations require explicit user confirmation via inline buttons.