laravel-telegram maintained by labrodev
Laravel Telegram
Stateless Telegram Bot API client for Laravel with webhook update parsing and secret-token verification. Every client call reads the bot token from config and hits the Telegram Bot API directly — the package stores nothing about chats, updates, or webhooks itself.
Installation
composer require labrodev/laravel-telegram
Publish the config file:
php artisan vendor:publish --tag=telegram-config
Set the environment variables:
TELEGRAM_BOT_TOKEN=123456:your-bot-token-from-botfather
TELEGRAM_BOT_USERNAME=YourBotUsername
TELEGRAM_WEBHOOK_SECRET=a-high-entropy-string-you-generate
Sending messages
use Labrodev\Telegram\Services\TelegramClient;
$telegramClient = new TelegramClient();
$telegramClient->sendMessage(
chatId: $chatId,
text: 'Hello from Laravel!',
options: ['parse_mode' => 'Markdown'],
);
Registering the webhook
Call setWebhook() once (from a console command or a one-off route) with your public webhook URL and the same secret configured as TELEGRAM_WEBHOOK_SECRET. Telegram echoes that secret back on every update it delivers:
use Labrodev\Telegram\Services\TelegramClient;
$telegramClient = new TelegramClient();
$telegramClient->setWebhook(
url: 'https://my-app.test/telegram/webhook',
secretToken: config('telegram.webhook_secret'),
allowedUpdates: ['message'],
);
Handling incoming updates
TelegramWebhookSecretVerifier and TelegramUpdateParser are both single-purpose services — invoke them directly rather than calling a named method. Verify the X-Telegram-Bot-Api-Secret-Token header before trusting the payload, then parse it into a TelegramCommand:
use Illuminate\Http\Request;
use Labrodev\Telegram\Services\TelegramUpdateParser;
use Labrodev\Telegram\Services\TelegramWebhookSecretVerifier;
class TelegramWebhookController
{
public function __invoke(
Request $request,
TelegramWebhookSecretVerifier $telegramWebhookSecretVerifier,
TelegramUpdateParser $telegramUpdateParser,
) {
if (! $telegramWebhookSecretVerifier($request->header('X-Telegram-Bot-Api-Secret-Token'))) {
abort(403);
}
$telegramCommand = $telegramUpdateParser($request->all());
if ($telegramCommand === null) {
return response()->noContent();
}
match ($telegramCommand->command) {
'start' => // handle /start, $telegramCommand->argument, $telegramCommand->chatId
default => null,
};
return response()->noContent();
}
}
TelegramWebhookSecretVerifier throws TelegramWebhookSecretMissing rather than returning false when telegram.webhook_secret isn't configured — that's a deployment mistake on your side, not an untrusted request, and should surface loudly (let it bubble into a 500) instead of being swallowed as an ordinary 403.
Exceptions
Labrodev\Telegram\Exceptions\TelegramAuthFailed— Telegram returned 401/403, or no bot token is configured.Labrodev\Telegram\Exceptions\TelegramRequestFailed— any other failed request.Labrodev\Telegram\Exceptions\TelegramWebhookSecretMissing—telegram.webhook_secretis not configured. Thrown byTelegramWebhookSecretVerifierinstead of failing closed, since this is a misconfiguration that needs fixing, not a rejected caller.
The first two carry fixed messages only. The bot token rides in the request URL path itself (https://api.telegram.org/bot{token}/...), so no URL, response body, or request detail is ever interpolated into an exception message.
Testing
composer test # pest
composer phpstan # larastan, level 7
composer pint # laravel preset
composer check # all of the above
License
MIT. See LICENSE.md.