# Telegram Bot SDK for PHP
Telegram Bot SDK (`irazasyed/telegram-bot-sdk`) is an unofficial PHP library (v3.x, current stable) that provides a fluent, object-oriented wrapper around the [Telegram Bot API](https://core.telegram.org/bots/api). It supports all major Bot API methods — sending messages, media, polls, stickers, inline keyboards, webhooks, and chat administration — via a single `Api` class that composes functionality through PHP traits. The library requires PHP ≥ 8.0, uses Guzzle for HTTP, and ships with first-class Laravel/Lumen integration via an auto-discovered service provider.
The SDK's architecture revolves around three core pillars: the `Api` class (single-bot usage), `BotsManager` (multi-bot management), and the command bus system. Every Telegram API method returns a typed object (e.g., `MessageObject`, `ChatObject`, `User`) rather than raw arrays. File uploads are handled uniformly through `InputFile`, keyboards are built with the fluent `Keyboard` builder, and update routing (long-polling or webhook) dispatches PSR-14-compatible events. Laravel users get a `Telegram` facade, an IoC-injected `BotsManager`, and the `telegram:webhook` Artisan command out of the box.
---
## Installation
Install via Composer. For Laravel, the service provider is auto-discovered.
```bash
composer require irazasyed/telegram-bot-sdk
# Laravel: publish the config
php artisan vendor:publish --tag=telegram-config
```
---
## Api — Instantiation
Single-bot entry point. Reads the token from a constructor argument or the `TELEGRAM_BOT_TOKEN` environment variable.
```php
use Telegram\Bot\Api;
use Telegram\Bot\Exceptions\TelegramSDKException;
// Basic instantiation
$telegram = new Api('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11');
// From environment variable TELEGRAM_BOT_TOKEN
$telegram = new Api();
// Async (non-blocking) requests + custom base URL
$telegram = new Api(
token: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
async: true,
baseBotUrl: 'https://my-local-bot-api.example.com/bot'
);
try {
$me = $telegram->getMe();
echo $me->username; // e.g., "MyAwesomeBot"
} catch (TelegramSDKException $e) {
echo 'Error: ' . $e->getMessage();
}
```
---
## BotsManager — Multi-Bot Management
Manages a pool of named bots, each with its own token and command set.
```php
use Telegram\Bot\BotsManager;
$manager = new BotsManager([
'default' => 'mainbot',
'async_requests' => false,
'bots' => [
'mainbot' => [
'token' => '111111:AAAA',
'commands' => [\App\Commands\StartCommand::class],
],
'supportbot' => [
'token' => '222222:BBBB',
],
],
'commands' => [\Telegram\Bot\Commands\HelpCommand::class], // global commands
]);
// Get default bot
$bot = $manager->bot();
// Get a specific bot
$supportBot = $manager->bot('supportbot');
// Reconnect (re-creates the instance)
$manager->reconnect('mainbot');
// Magic pass-through to the default bot
$manager->sendMessage(['chat_id' => 123456789, 'text' => 'Hello from manager!']);
```
---
## getMe — Test Bot Authentication
Validates the bot token and returns basic bot information as a `User` object.
```php
use Telegram\Bot\Api;
$telegram = new Api('YOUR-BOT-TOKEN');
$me = $telegram->getMe();
echo $me->id; // 987654321
echo $me->username; // "MyAwesomeBot"
echo $me->first_name; // "My Awesome"
echo $me->can_join_groups; // true/false
```
---
## sendMessage — Send Text Messages
Sends a plain or formatted text message to a chat, group, or channel.
```php
use Telegram\Bot\Api;
$telegram = new Api('YOUR-BOT-TOKEN');
// Plain text
$message = $telegram->sendMessage([
'chat_id' => 123456789,
'text' => 'Hello, World!',
]);
// HTML-formatted, with link preview disabled, and a reply
$message = $telegram->sendMessage([
'chat_id' => '@mychannel',
'text' => 'Bold and link',
'parse_mode' => 'HTML',
'disable_web_page_preview' => true,
'reply_to_message_id' => 42,
'protect_content' => true,
]);
echo $message->message_id; // 101
echo $message->chat->id; // 123456789
```
---
## forwardMessage / copyMessage — Forward and Copy Messages
Forwards a message (with original sender attribution) or copies it (without attribution).
```php
// Forward a message — shows "Forwarded from Original Sender"
$forwarded = $telegram->forwardMessage([
'chat_id' => 987654321, // destination
'from_chat_id' => 123456789, // source chat
'message_id' => 101,
]);
// Copy a message — no forwarding header
$copied = $telegram->copyMessage([
'chat_id' => 987654321,
'from_chat_id' => 123456789,
'message_id' => 101,
'caption' => 'Here is a copy of the original message.',
'parse_mode' => 'Markdown',
]);
echo $copied->message_id; // new message ID in destination chat
```
---
## sendPhoto — Send Photos
Sends a photo by local path, URL, or a Telegram `file_id`.
```php
use Telegram\Bot\FileUpload\InputFile;
// From URL
$message = $telegram->sendPhoto([
'chat_id' => 123456789,
'photo' => 'https://example.com/image.jpg',
'caption' => 'A photo from the web',
]);
// Upload a local file
$message = $telegram->sendPhoto([
'chat_id' => 123456789,
'photo' => InputFile::create('/path/to/photo.jpg', 'photo.jpg'),
'caption' => 'A **local** photo',
'parse_mode' => 'Markdown',
]);
// Re-use by file_id (fastest)
$message = $telegram->sendPhoto([
'chat_id' => 123456789,
'photo' => 'AgACAgIAAxkBAAI...file_id_here',
]);
echo $message->photo[0]->file_id; // stored file_id for reuse
```
---
## sendDocument / sendAudio / sendVideo / sendVoice — Send Media Files
Sends general files, audio, video, or voice messages using `InputFile`.
```php
use Telegram\Bot\FileUpload\InputFile;
// Send a PDF document
$telegram->sendDocument([
'chat_id' => 123456789,
'document' => InputFile::create('/path/to/report.pdf'),
'caption' => 'Monthly Report',
]);
// Send an MP3 audio file with metadata
$telegram->sendAudio([
'chat_id' => 123456789,
'audio' => InputFile::create('/path/to/song.mp3'),
'title' => 'My Song',
'performer' => 'The Artist',
'duration' => 210,
]);
// Send an MP4 video
$telegram->sendVideo([
'chat_id' => 123456789,
'video' => InputFile::create('/path/to/video.mp4'),
'caption' => 'Demo video',
'supports_streaming' => true,
'width' => 1920,
'height' => 1080,
]);
// Send OGG voice note
$telegram->sendVoice([
'chat_id' => 123456789,
'voice' => InputFile::create('/path/to/note.ogg'),
'duration' => 15,
]);
```
---
## sendMediaGroup — Send Albums
Sends 2–10 photos, videos, audios, or documents as an album.
```php
use Telegram\Bot\FileUpload\InputFile;
$telegram->sendMediaGroup([
'chat_id' => 123456789,
'media' => json_encode([
[
'type' => 'photo',
'media' => 'https://example.com/photo1.jpg',
'caption' => 'First photo',
],
[
'type' => 'photo',
'media' => 'https://example.com/photo2.jpg',
],
[
'type' => 'video',
'media' => 'https://example.com/clip.mp4',
],
]),
]);
```
---
## sendPoll — Send Polls
Sends a native regular or quiz poll to a chat.
```php
// Regular poll (anonymous, multiple answers allowed)
$message = $telegram->sendPoll([
'chat_id' => 123456789,
'question' => 'What is your favorite language?',
'options' => ['PHP', 'Python', 'TypeScript', 'Rust'],
'is_anonymous' => true,
'allows_multiple_answers' => true,
'open_period' => 300, // closes after 5 minutes
]);
// Quiz poll (with correct answer and explanation)
$telegram->sendPoll([
'chat_id' => 123456789,
'question' => 'What does SDK stand for?',
'options' => ['Software Development Kit', 'System Design Key', 'Secure Data Kernel'],
'type' => 'quiz',
'correct_option_id' => 0,
'explanation' => 'SDK = *Software Development Kit*',
'explanation_parse_mode' => 'Markdown',
]);
echo $message->poll->id; // the poll identifier
```
---
## sendChatAction — Send Chat Actions
Broadcasts a typing/upload indicator so users see the bot is "busy".
```php
use Telegram\Bot\Actions;
// Show "typing..." indicator
$telegram->sendChatAction([
'chat_id' => 123456789,
'action' => Actions::TYPING, // 'typing'
]);
// Show "uploading photo" indicator
$telegram->sendChatAction([
'chat_id' => 123456789,
'action' => Actions::UPLOAD_PHOTO, // 'upload_photo'
]);
// Available actions: typing, upload_photo, record_video, upload_video,
// record_voice, upload_voice, upload_document, choose_sticker,
// find_location, record_video_note, upload_video_note
```
---
## InputFile — File Upload Helper
Wraps local files, remote URLs, PHP resources, and PSR-7 streams for upload methods.
```php
use Telegram\Bot\FileUpload\InputFile;
// From local path (auto-detects filename)
$file = InputFile::create('/tmp/document.pdf');
// From local path with explicit filename
$file = InputFile::create('/tmp/document.pdf', 'report-2024.pdf');
// Create in-memory from a string (no disk write needed)
$csvContent = "name,age\nAlice,30\nBob,25";
$file = InputFile::createFromContents($csvContent, 'users.csv');
// From a PHP resource
$resource = fopen('/tmp/image.jpg', 'r');
$file = InputFile::create($resource, 'photo.jpg');
// Use with any upload method
$telegram->sendDocument([
'chat_id' => 123456789,
'document' => $file,
]);
// Check if the file is remote
$remoteFile = InputFile::create('https://example.com/file.pdf');
$remoteFile->isFileRemote(); // true
```
---
## setWebhook / getWebhookInfo / deleteWebhook — Webhook Management
Registers an HTTPS URL to receive updates instead of polling.
```php
// Register a webhook
$result = $telegram->setWebhook([
'url' => 'https://myapp.example.com/telegram/webhook',
'allowed_updates' => ['message', 'callback_query', 'inline_query'],
'max_connections' => 40,
]);
// $result === true on success
// Retrieve current webhook status
$info = $telegram->getWebhookInfo();
echo $info->url; // 'https://myapp.example.com/telegram/webhook'
echo $info->pending_update_count; // 0
echo $info->has_custom_certificate; // false
// Remove the webhook (switch back to getUpdates)
$telegram->deleteWebhook(); // or $telegram->removeWebhook()
```
---
## getUpdates — Long Polling
Fetches incoming updates using long-polling (alternative to webhooks).
```php
use Telegram\Bot\Api;
$telegram = new Api('YOUR-BOT-TOKEN');
// Basic polling loop
$offset = 0;
while (true) {
$updates = $telegram->getUpdates([
'offset' => $offset,
'limit' => 100,
'timeout' => 30,
'allowed_updates' => ['message', 'callback_query'],
]);
foreach ($updates as $update) {
$offset = $update->update_id + 1;
if ($update->getMessage()) {
$chatId = $update->getMessage()->chat->id;
$text = $update->getMessage()->text ?? '';
$telegram->sendMessage([
'chat_id' => $chatId,
'text' => 'You said: ' . $text,
]);
}
}
}
```
---
## getWebhookUpdate — Process Webhook Updates
Reads an inbound update from the raw PHP input (called inside your webhook handler).
```php
use Telegram\Bot\Api;
// In your webhook endpoint (e.g., /telegram/webhook)
$telegram = new Api('YOUR-BOT-TOKEN');
$update = $telegram->getWebhookUpdate();
$message = $update->getMessage();
if ($message) {
$telegram->sendMessage([
'chat_id' => $message->chat->id,
'text' => 'Got your message: ' . $message->text,
]);
}
// With event dispatching disabled
$update = $telegram->getWebhookUpdate(shouldDispatchEvents: false);
// From a PSR-7 request object
$update = $telegram->getWebhookUpdate(request: $psrRequest);
```
---
## editMessageText / editMessageCaption / deleteMessage — Edit Messages
Modifies or removes previously sent messages.
```php
// Edit text content
$telegram->editMessageText([
'chat_id' => 123456789,
'message_id' => 101,
'text' => 'Updated message content',
'parse_mode' => 'HTML',
]);
// Edit only the caption of a media message
$telegram->editMessageCaption([
'chat_id' => 123456789,
'message_id' => 202,
'caption' => 'New caption text',
]);
// Edit an inline message (sent via inline query)
$telegram->editMessageText([
'inline_message_id' => 'AAAA_inline_id',
'text' => 'Inline message updated!',
]);
// Delete a single message
$telegram->deleteMessage([
'chat_id' => 123456789,
'message_id' => 101,
]);
// Bulk delete messages (up to 100)
$telegram->deleteMessages([
'chat_id' => 123456789,
'message_ids' => [101, 102, 103, 104],
]);
```
---
## Keyboard — Build Reply and Inline Keyboards
Fluent builder for `ReplyKeyboardMarkup`, `InlineKeyboardMarkup`, `ReplyKeyboardRemove`, and `ForceReply`.
```php
use Telegram\Bot\Keyboard\Keyboard;
// Reply keyboard (persistent on-screen buttons)
$replyKeyboard = Keyboard::make()
->setResizeKeyboard(true)
->setOneTimeKeyboard(true)
->row([
Keyboard::button('Yes'),
Keyboard::button('No'),
])
->row([
Keyboard::button('Cancel'),
]);
$telegram->sendMessage([
'chat_id' => 123456789,
'text' => 'Please choose:',
'reply_markup' => $replyKeyboard,
]);
// Inline keyboard (buttons attached to the message)
$inlineKeyboard = Keyboard::make()->inline()
->row([
Keyboard::inlineButton(['text' => 'Visit Website', 'url' => 'https://telegram.org']),
Keyboard::inlineButton(['text' => 'Callback', 'callback_data' => 'action:approve']),
])
->row([
Keyboard::inlineButton(['text' => 'Inline Search', 'switch_inline_query' => 'query']),
]);
$telegram->sendMessage([
'chat_id' => 123456789,
'text' => 'Choose an option:',
'reply_markup' => $inlineKeyboard,
]);
// Remove the custom keyboard
$telegram->sendMessage([
'chat_id' => 123456789,
'text' => 'Keyboard removed.',
'reply_markup' => Keyboard::remove(),
]);
// Force the user to reply
$telegram->sendMessage([
'chat_id' => 123456789,
'text' => 'Please reply to this message.',
'reply_markup' => Keyboard::forceReply(),
]);
```
---
## Command System — Creating and Registering Commands
Extends `Command` to handle bot slash commands with argument parsing and reply helpers.
```php
use Telegram\Bot\Commands\Command;
// Define a command
class StartCommand extends Command
{
protected string $name = 'start';
protected array $aliases = ['begin', 'go'];
protected string $description = 'Start interacting with the bot.';
public function handle(): void
{
$this->replyWithMessage([
'text' => "Welcome! I'm ready to help.\nSend /help to see all commands.",
'parse_mode' => 'HTML',
]);
}
}
// Command with parsed arguments: /echo {word} {times:\d+}
class EchoCommand extends Command
{
protected string $name = 'echo';
protected string $description = 'Echoes a word N times.';
protected string $pattern = '{word} {times:\d+}';
public function handle(): void
{
$word = $this->argument('word', 'hello');
$times = (int) $this->argument('times', 1);
$this->replyWithMessage([
'text' => implode(' ', array_fill(0, $times, $word)),
]);
}
}
// Register and process commands
use Telegram\Bot\Api;
$telegram = new Api('YOUR-BOT-TOKEN');
$telegram->addCommands([
StartCommand::class,
EchoCommand::class,
\Telegram\Bot\Commands\HelpCommand::class,
]);
// Process incoming update through the command bus
$updates = $telegram->getUpdates();
foreach ($updates as $update) {
$telegram->processCommand($update); // dispatches to matching command
}
```
---
## Event System — Listening to Updates
Attach listeners to update events for custom routing logic without a command bus.
```php
use Telegram\Bot\Api;
use Telegram\Bot\Events\UpdateEvent;
$telegram = new Api('YOUR-BOT-TOKEN');
// Listen for ALL updates
$telegram->on(UpdateEvent::NAME, function (UpdateEvent $event): void {
$update = $event->update;
echo 'Update ID: ' . $update->update_id . PHP_EOL;
});
// Listen only for message updates
$telegram->on('message', function (UpdateEvent $event): void {
$message = $event->update->getMessage();
echo 'Text: ' . ($message->text ?? 'non-text message') . PHP_EOL;
});
// Listen for a specific message type (e.g., photo messages)
$telegram->on('message.photo', function (UpdateEvent $event): void {
$photos = $event->update->getMessage()->photo;
$fileId = end($photos)['file_id']; // largest photo
echo 'Photo file_id: ' . $fileId . PHP_EOL;
});
// Trigger event dispatch via getUpdates
$telegram->getUpdates(['timeout' => 30]);
```
---
## Chat Administration Methods
Manage members, permissions, and settings of groups, supergroups, and channels.
```php
// Get chat info
$chat = $telegram->getChat(['chat_id' => -1001234567890]);
echo $chat->title; // "My Group"
echo $chat->type; // "supergroup"
// Get member count
$count = $telegram->getChatMemberCount(['chat_id' => -1001234567890]);
// Get list of admins
$admins = $telegram->getChatAdministrators(['chat_id' => -1001234567890]);
foreach ($admins as $admin) {
echo $admin->user->username . ' (' . $admin->status . ')' . PHP_EOL;
}
// Ban a user for 7 days (604800 seconds)
$telegram->banChatMember([
'chat_id' => -1001234567890,
'user_id' => 111111111,
'until_date' => time() + 604800,
]);
// Unban a previously banned user
$telegram->unbanChatMember([
'chat_id' => -1001234567890,
'user_id' => 111111111,
'only_if_banned' => true,
]);
// Restrict a user (mute: no messages, no media)
$telegram->restrictChatMember([
'chat_id' => -1001234567890,
'user_id' => 222222222,
'permissions' => json_encode([
'can_send_messages' => false,
'can_send_media_messages' => false,
]),
'until_date' => time() + 3600, // 1 hour
]);
// Create an invite link
$inviteLink = $telegram->createChatInviteLink([
'chat_id' => -1001234567890,
'name' => 'VIP Invite',
'member_limit' => 50,
'expire_date' => time() + 86400,
]);
echo $inviteLink->invite_link;
// Pin a message
$telegram->pinChatMessage([
'chat_id' => -1001234567890,
'message_id' => 500,
'disable_notification' => true,
]);
```
---
## Laravel Integration — Facade and Config
Use the `Telegram` facade or inject `BotsManager`/`Api` via the service container.
```php
// config/telegram.php — after php artisan vendor:publish --tag=telegram-config
return [
'default' => 'mybot',
'bots' => [
'mybot' => [
'token' => env('TELEGRAM_BOT_TOKEN'),
'webhook_url' => env('TELEGRAM_WEBHOOK_URL'),
'commands' => [
\App\Telegram\Commands\StartCommand::class,
\App\Telegram\Commands\HelpCommand::class,
],
],
],
'async_requests' => env('TELEGRAM_ASYNC_REQUESTS', false),
'resolve_command_dependencies' => true,
'commands' => [
\Telegram\Bot\Commands\HelpCommand::class,
],
];
```
```php
// In a controller — using the Facade
use Telegram\Bot\Laravel\Facades\Telegram;
class BotController extends Controller
{
public function webhook(): \Illuminate\Http\Response
{
$update = Telegram::getWebhookUpdate();
Telegram::commandsHandler(true); // process commands automatically
return response('OK');
}
public function notify(int $chatId, string $text): void
{
Telegram::sendMessage(['chat_id' => $chatId, 'text' => $text]);
}
}
// Using dependency injection
use Telegram\Bot\BotsManager;
class NotificationService
{
public function __construct(private BotsManager $telegram) {}
public function send(string $bot, int $chatId, string $text): void
{
$this->telegram->bot($bot)->sendMessage([
'chat_id' => $chatId,
'text' => $text,
]);
}
}
```
```bash
# Artisan webhook management
php artisan telegram:webhook --setup # register the webhook URL
php artisan telegram:webhook --info # display current webhook status
php artisan telegram:webhook --remove # remove the webhook
php artisan telegram:webhook mybot --setup # target a specific named bot
php artisan telegram:webhook --all --info # info for all configured bots
```
---
## getFile — Download Files
Retrieves file metadata for constructing a download URL.
```php
// Get file info from a file_id (e.g., obtained from a received photo/document)
$file = $telegram->getFile(['file_id' => 'BQACAgIAAxkBAAI...']);
echo $file->file_id; // unique file identifier
echo $file->file_path; // e.g., "photos/file_123.jpg"
echo $file->file_size; // bytes
// Construct the download URL manually
$token = 'YOUR-BOT-TOKEN';
$fileUrl = "https://api.telegram.org/file/bot{$token}/{$file->file_path}";
// Download with Guzzle or file_get_contents
$contents = file_get_contents($fileUrl);
file_put_contents('/tmp/downloaded_file.jpg', $contents);
```
---
## Summary
The Telegram Bot SDK for PHP covers the full spectrum of bot development needs: simple personal bots sending notifications to a single chat, multi-bot SaaS platforms managed through `BotsManager`, event-driven bots that react to specific update types via the PSR-14 event system, and command-driven chatbots with argument parsing and IoC dependency injection. Every API method follows the same uniform pattern — pass an associative array of parameters, receive a typed object — making the codebase predictable and easy to test.
For Laravel applications, the SDK is a drop-in package: publish the config, set `TELEGRAM_BOT_TOKEN` in `.env`, register your command classes, and use the `Telegram` facade or inject `BotsManager` wherever needed. The `telegram:webhook` Artisan command handles the webhook lifecycle (setup, teardown, status inspection) without touching the API manually. For non-Laravel PHP projects, instantiate `Api` directly or use `BotsManager` with a plain config array, attaching an optional PSR-11 container for command dependency resolution.