Skip to content

The Telegram Client ​

The Tueen\Telegram\Telegram class (conventionally instantiated as $bot) is the primary entry point and client facade of the tueen/telegram library. It provides a unified, strictly typed interface for sending Bot API requests, listening for updates, managing multi-step flows, and resolving contextual parameters.


🚀 1. Instantiation ​

You can initialize the client either directly with your bot token or via a pre-built Config object:

Basic Instantiation ​

php
use Tueen\Telegram\Telegram;

$bot = new Telegram('YOUR_BOT_TOKEN');

Advanced Instantiation with ConfigBuilder ​

For production environments requiring custom timeouts, proxy connections, retry policies, or test servers:

php
use Tueen\Telegram\Telegram;

$config = Telegram::create('YOUR_BOT_TOKEN')
    ->withTimeout(30.0)
    ->withRetryCount(3)
    ->build();

$bot = new Telegram($config);

For a full list of networking and runtime settings, see the Configuration Reference.


⚡ 2. The Three Primary Roles of $bot ​

In your application, the $bot instance serves three essential purposes:

1. Direct Bot API Client ​

You can invoke all Telegram Bot API methods dynamically with full IDE autocompletion and named arguments:

php
$bot->sendMessage(
    chatId: 123456789,
    text: 'Hello from tueen/telegram!'
);

Learn more in Calling Methods & Types.

2. Update Router & Dispatcher ​

The client listens for incoming updates and dispatches them to closures, classes, or attribute controllers:

php
// Register a command route:
$bot->onCommand('start', function (Update $update, Telegram $bot) {
    $bot->sendMessage(text: 'Welcome! How can I assist you today?');
});

// Run the bot via Webhook, Polling, or AutoMode:
$bot->run();

Learn more in Update Routing & Attributes and Running Modes.

3. Contextual Entity Resolver (PHP 8.4 Property Hooks) ​

During update processing, $bot automatically tracks the active update and provides instant shortcuts to chat, user, and message identifiers via modern PHP 8.4 Property Hooks:

php
$chatId  = $bot->chatId;  // e.g. 123456789
$userId  = $bot->userId;  // e.g. 987654321
$message = $bot->message; // Current ?Message instance

Tip: Legacy method calls such as $bot->chatId() continue to work with a deprecation notice for full backward compatibility. Learn more in Update & Message Helpers.


💡 3. Client Best Practices ​

Here are the recommended patterns to keep in mind when working with the $bot instance:

1. Always Use PHP Named Arguments ​

Telegram Bot API methods accept many optional parameters. Named arguments protect your code against parameter order changes and enable Contextual Auto-Injection (where repetitive parameters like chatId are automatically resolved from the active update):

php
// ✅ RECOMMENDED: Order-independent, self-documenting, auto-injects chatId:
$bot->sendMessage(
    text: 'Order confirmed successfully.',
    parseMode: ParseMode::HTML
);

// ❌ AVOID: Fragile positional arguments with trailing nulls:
$bot->sendMessage(123456, 'Order confirmed successfully.', null, null, null, null, 'HTML');

2. Reusing a Single Client Instance ​

Telegram is lightweight and designed to be created once. In modern frameworks (such as Laravel, Symfony, or Slim), register $bot as a singleton in your dependency injection container:

php
// Example: Registering as a singleton in a PSR-11 container:
$container->singleton(Telegram::class, function () {
    return new Telegram(getenv('TELEGRAM_BOT_TOKEN'));
});

3. Organizing Complex Bots with Controllers ​

For simple bots, defining routes with closures directly in your script is quick and convenient. As your application grows, organize your commands and actions into dedicated Controller classes:

php
// Register a dedicated controller class decorated with routing attributes:
$bot->registerController(OrderController::class);

See Attribute-Driven Controllers for examples of using #[OnCommand] and #[OnCallbackQuery].


🏛️ 4. Architecture & Decoupled Subsystems ​

Under the hood, Telegram is not a monolithic class holding all bot logic. Instead, it uses a modular composition architecture that delegates work to single-responsibility components:

flowchart LR
    subgraph InboundTrack ["Inbound Pipeline (Receiving Updates)"]
        direction TB
        TelegramIn[("Telegram Bot API")] -->|Webhook or Polling| Runner["RunningMode"]
        Runner --> Dispatcher["UpdateDispatcher"]
        Dispatcher --> UpdatePipes["Global Middlewares"]
        
        UpdatePipes --> PriorityCheck{"Priority Route?"}
        PriorityCheck -->|Yes| ConsultFlow{"Flow Allows?"}
        ConsultFlow -->|Allowed| PriorityHandler["Priority Handler"]
        
        PriorityCheck -->|No| FlowCheck{"Active Flow?"}
        ConsultFlow -->|Vetoed| FlowCheck
        
        FlowCheck -->|Yes| FlowStep["Execute Flow Step"]
        FlowStep --> FlowDecision{"Step Handled?"}
        FlowDecision -->|Yes| FlowDone["Save Flow State"]
        FlowDecision -->|Pass Through| RouterEngine["Router & Route Groups"]
        
        FlowCheck -->|No| RouterEngine
        RouterEngine -->|Matched Route| RoutePipes["Route Middlewares"]
        RoutePipes --> AutoWire["Auto-Wiring & Type Casting"]
        AutoWire --> RouteHandlers["Route Handlers"]
        RouterEngine -->|Unmatched| Fallback["Fallback Handler"]
    end

    subgraph OutboundTrack ["Outbound Pipeline (Sending Requests)"]
        direction TB
        Context["ContextResolver (Auto-Inject)"]
        Context --> HttpPipes["HTTP Middlewares (Retry, RateLimit)"]
        HttpPipes --> Client["TelegramClient (PSR-18)"]
        Client --> Pool["Persistent cURL Connection Pool"]
        Pool --> TelegramOut[("Telegram Bot API")]
    end

    %% Handlers send API requests back through Outbound Pipeline
    PriorityHandler -->|Reply or Send| Context
    FlowStep -->|Reply or Send| Context
    RouteHandlers -->|Reply or Send| Context
    Fallback -.->|Optional Reply| Context
    DirectCall["Queue Worker or Scoped Worker"] -.-> Context

When to Access Subsystems Directly: ​

Most of the time, you interact exclusively with the $bot facade. However, you can access underlying subsystems when building low-level extensions, worker queues, persistent daemons, or custom integrations:

php
use Tueen\Telegram\Telegram;
use Tueen\Telegram\Client\CurlHttpClient;

$bot = new Telegram('YOUR_BOT_TOKEN');

// 1. Pure HTTP client (useful for worker queue jobs that only call API methods without processing updates):
$client = $bot->client;
$me = $client->getMe();

// 2. Underlying router instance (inspect or manipulate route collections directly):
$router = $bot->router;

// 3. Flow state manager (for custom state stores or manual session manipulation):
$flowManager = $bot->flowManager;

// 4. Context parameter resolver (manual default binding or contextual entity inspection):
$context = $bot->context;
$activeChatId = $context->chatId;

// 5. Scoped Client for Persistent Worker Engines (FrankenPHP, RoadRunner, Swoole, Laravel Octane):
// Clones the client into a thread-safe, isolated instance with dedicated context per update:
$scopedBot = $bot->scoped($incomingUpdate);

// 6. PSR-11 Dependency Injection Container:
// Connect an external DI container (e.g. Laravel Container, PHP-DI, Symfony DI) for controller auto-wiring:
$bot->container = $myContainer;

// 7. Persistent HTTP Connection Pool Management:
// Check cached TCP/TLS keep-alive handles or flush them during worker maintenance:
$poolCount = CurlHttpClient::getPoolCount();
CurlHttpClient::closeAllHandles();

🧭 5. Complete Method & Property Reference ​

Below is the comprehensive catalog of all constants, properties, and methods provided on the Telegram class, grouped by architectural responsibility. Every item features syntax-highlighted signatures, parameter types, default values, and status badges.

🏛️ Class Constants & Public Properties ​

public const string BOT_API_VERSION
→stringConstant
Canonical Telegram Bot API version currently supported and validated against.
public const string API_VERSION = self::BOT_API_VERSION
Alias
👉DX Shorthand: Alias for Telegram::BOT_API_VERSION
Shorthand alias for BOT_API_VERSION for cleaner references.
public ?Update $update = null
→?UpdateProperty Hook
Current resolved Update instance for the active request lifecycle. Defaults to null until resolved by WebhookMode or PollingMode.
private(set) ContextResolver $context
→ContextResolverAsymmetric Visibility
Contextual parameter resolver instance automatically bound to $update for argument auto-injection.
private(set) TelegramClient $client
→TelegramClientAsymmetric Visibility
Underlying pure HTTP transport client handling serialization, multipart uploads, and PSR-18 communication.
private(set) UpdateDispatcher $dispatcher
→UpdateDispatcherAsymmetric Visibility
Incoming update dispatcher managing the middleware pipeline, route execution, and exception catchers.
private(set) Config $config
→ConfigAsymmetric Visibility
Immutable client configuration driving timeouts, tokens, and networking.
public RunningModeInterface $runningMode
→RunningModeInterfaceProperty Hook
Active running mode instance (e.g. WebhookMode, PollingMode, or AutoMode).
public mixed $container
→mixedProperty Hook
Configured PSR-11 dependency injection container or callable resolver.
public FlowManager $flowManager
→FlowManagerProperty Hook
Multi-step conversational flow manager and state orchestrator.
public Router $router
→RouterProperty Hook
Incoming update router and controller registry.

A. Initialization & Testing Factory ​

Telegram::create(string $botToken)
Factory
Initializes a fluent ConfigBuilder for configuring network timeouts, persistent cURL handles, proxies, retries, and running modes.
Telegram::fake(array $responses = [], string $botToken = 'FAKE_BOT_TOKEN')
Testing
Creates an in-memory testing fake client with recording capabilities and assertion helpers (assertSent, assertSentCount, assertNotSent).
new Telegram(string|Config $tokenOrConfig)
→TelegramConstructor
Instantiates the primary Telegram client directly using either a plain bot token string or a pre-built immutable Config object.

B. Execution & Running Modes ​

run(mixed ...$handlers)
→mixedCanonical
Executes update ingestion using the configured running mode (WebhookMode or PollingMode), dispatching updates through middlewares and routes.
autoRun(mixed ...$handlers)
→mixedAdaptive
Zero-config adaptive runner: automatically selects PollingMode in CLI environments and WebhookMode under HTTP server processes.
useAutoMode(?PollingMode $polling = null, ?WebhookMode $webhook = null, bool $autoDeleteWebhook = false, bool $dropPendingUpdatesOnDelete = false, ?callable $detector = null)
→static
Explicitly configures AutoMode with custom runner instances, automated webhook cleanup on shutdown, and optional environment detection overrides.
setRunningMode(RunningModeInterface $mode)
→static
Sets an explicit running mode instance (e.g. custom WebhookMode, PollingMode, or user-defined runner).
poll(int $timeout = 30, int $limit = 100, ?array $allowedUpdates = null)
→Generator<int, Update>Streaming
Returns a lazy PHP generator yielding incoming Update objects via continuous long-polling with automatic offset tracking.

C. Update Pipeline & Middleware ​

middleware(callable $middleware)
→staticCanonical
Appends an update middleware to the incoming dispatch pipeline. Receives ($update, $next, $bot).
use(callable $middleware)
→staticAlias
👉DX Shorthand: Alias for middleware()
Developer experience shorthand alias for middleware(), popularized by Telegraf and grammY.
pipe(MiddlewareInterface|Closure $middleware)
→staticOutbound
Appends an outbound HTTP request middleware to the client transport pipeline (e.g. RetryMiddleware, RateLimitMiddleware, LoggingMiddleware).
onBeforeRequest(callable $callback)
→staticHook
Lifecycle hook triggered immediately before sending any outbound HTTP request to Telegram. Receives ($request, $config).
onAfterRequest(callable $callback)
→staticHook
Lifecycle hook triggered after receiving a raw HTTP response. Receives ($response, $request).
onError(callable $callback)
→staticHook
Lifecycle hook triggered when a transport error or HTTP exception occurs. Receives ($throwable, $request).
onResponse(callable $callback)
→staticHook
Lifecycle hook triggered when a final parsed response (Type or Error object) is produced. Receives ($type, $request).

D. Exception & Error Handling ​

catch(string|callable $exceptionOrHandler, ?callable $handler = null)
→staticCanonical
Registers a typed exception catcher for errors thrown during update processing. Matches exact exception classes or any \Throwable.
onUpdateError(callable $handler)
→staticAlias
👉DX Shorthand: Alias for catch(\Throwable::class, $handler)
Convenience shorthand alias registering a universal error catcher for all unhandled update exceptions.
handleUpdateException(\Throwable $e, Update $update)
→boolInternal
Dispatches an uncaught exception through registered error catchers. Returns true if handled by a matching catcher.

E. Update Routing & Controllers ​

group(array|callable $attributesOrCallback, ?callable $callback = null)
→staticRouting
Groups related routes with shared prefixes, middlewares, or chat-type scopes (e.g. $bot->group(['prefix' => 'admin_'], function ($bot) { ... })).
onCommand(string $command, mixed $handler, bool $priority = false)
→Route
Matches bot commands (e.g. 'start', '/help') with automatic command argument parsing. Returns a Route instance supporting ->middleware(), ->asPrivate(), ->where().
onCallbackQuery(?string $pattern, mixed $handler, bool $priority = false)
→Route
Matches inline keyboard callback queries against an optional regex or placeholder pattern ('item:{id}'). Returns a fluent Route instance.
onMessage(?string $pattern, mixed $handler, bool $priority = false)
→Route
Matches text messages against an optional regex pattern or exact match. Returns a fluent Route instance.
onText(?string $pattern, mixed $handler, bool $priority = false)
→RouteAlias
👉DX Shorthand: Alias for onMessage()
Convenience shorthand alias for onMessage() matching text messages.
onInlineQuery(?string $pattern, mixed $handler, bool $priority = false)
→Route
Matches inline search queries with optional regex filtering. Returns a fluent Route instance.
on(UpdateType|string $type, mixed $handler, bool $priority = false)
→Route
Matches any Telegram update type (e.g. UpdateType::Message, UpdateType::CallbackQuery, or 'chat_member'). Returns a fluent Route instance.
onFallback(mixed $handler)
→staticFallback
Registers a default fallback handler invoked when no route, command, or active conversational flow matches the incoming update.
registerController(string|object $controller)
→static
Scans and registers an attribute-annotated controller class or object instance decorated with #[OnCommand], #[OnCallbackQuery], etc.
router()
→Router
Retrieves or initializes the underlying Router instance for custom route group manipulation.
handle(mixed ...$handlers)
→static
Appends raw update handler callables or invokable handler classes directly to the dispatcher queue.
invokeHandler(mixed $handler, Update $update)
→mixedDispatcher
Resolves parameter dependencies via the DI container / ContextResolver and executes a single update handler.

F. Multi-Step Conversational Flows ​

flow(int|string|null $chatId = null, ?int $userId = null, ?Update $update = null)
→FlowSession
Retrieves a fluent FlowSession for interacting with the active conversation, setting step state, or retrieving stored session data.
startFlow(string $flowClass, ?Update $update = null, string $initialStep = 'start', array $initialData = [])
→Flow
Initiates a multi-step conversation flow for the resolved chat and user, transitioning immediately to $initialStep.
hasActiveFlow(int|string|null $chatId = null, ?int $userId = null, ?Update $update = null)
→bool
Checks whether the chat/user currently has an active, unfinished conversation flow in persistent storage.
getActiveFlow(int|string|null $chatId = null, ?int $userId = null, ?Update $update = null)
→?Flow
Instantiates and returns the active Flow object populated with current state, or null if no flow is active.
getActiveFlowClass(int|string|null $chatId = null, ?int $userId = null, ?Update $update = null)
→?string
Returns the fully-qualified class string of the active flow without instantiating it.
flowBack(int|string|null $chatId = null, ?int $userId = null, ?string $replyMessage = null, ?Update $update = null)
→bool
Navigates the conversation back one step using the internal flow history stack, optionally sending a reply message.
cancelFlow(int|string|null $chatId = null, ?int $userId = null, ?string $replyMessage = 'Operation cancelled.', ?Update $update = null)
→bool
Cancels the active conversation, triggers onCancel() hooks, and wipes state from storage.
finishFlow(int|string|null $chatId = null, ?int $userId = null, ?Update $update = null)
→bool
Marks the active conversation as successfully completed and cleans up persistent storage.
flowManager()
→FlowManager
Returns the underlying FlowManager state orchestrator managing storage drivers and transition hooks.
setFlowStore(StateStoreInterface $store)
→static
Replaces the state driver with a custom implementation (e.g. MemoryStateStore, FileStateStore, Redis, or database).
setRootFlow(?string $flowClass)
→static
Configures a default/root Flow class to automatically launch when an idle user sends a message or on /start.

G. Contextual Accessors & Property Hooks ​

$bot->chatId
→?intProperty Hook
Resolves the active chat ID (extracted from message->chat->id, callback_query->message->chat->id, etc.).
$bot->userId
→?intProperty Hook
Resolves the active user ID from the current update (from->id).
$bot->messageId
→?intProperty Hook
Resolves the active message ID from the current update (message->message_id).
$bot->businessConnectionId
→?stringProperty Hook
Resolves the active Telegram Business connection ID for enterprise bots.
$bot->messageThreadId
→?intProperty Hook
Resolves the active forum topic thread ID for supergroups.
$bot->inlineMessageId
→?stringProperty Hook
Resolves the inline message identifier for updates initiated via inline queries.
$bot->callbackQueryId
→?stringProperty Hook
Resolves the active callback query ID from an inline button interaction.
$bot->inlineQueryId
→?stringProperty Hook
Resolves the active inline query ID.
$bot->shippingQueryId
→?stringProperty Hook
Resolves the active shipping query ID for e-commerce checkout flows.
$bot->preCheckoutQueryId
→?stringProperty Hook
Resolves the active pre-checkout query ID before payment finalization.
$bot->directMessagesTopicId
→?intProperty Hook
Resolves the direct messages forum topic ID in Telegram Business.
$bot->guestQueryId
→?stringProperty Hook
Resolves the guest query ID for anonymous web interactions.
$bot->chat
→?ChatProperty Hook
Extracts and returns the primary Chat type object from the current update.
$bot->user
→?UserProperty Hook
Extracts and returns the primary User type object from the current update.
$bot->message
→?MessageProperty Hook
Extracts and returns the primary Message type object from the current update.
reply(string|Text $text, mixed ...$args)
→mixedShortcut
Direct convenience shortcut to send a text message to the active chat in context without specifying chatId manually.
replyChunked(string|Text $text, int $chunkSize = 4096, mixed ...$args)
→list<mixed>Chunking
Replies with a long text or Text builder instance, splitting messages intelligently at sentence and newline boundaries to respect the 4096 character limit.
sendMessageChunked(string|Text $text, int $chunkSize = 4096, int|string|null $chatId = null, mixed ...$args)
→list<mixed>Chunking
Splits long text into multiple sequential messages sent to the target chat without breaking words or mangling newlines.
bindDefault(string $param, callable $resolver)
→static
Binds a custom contextual resolver for any Bot API method parameter (e.g. auto-injecting custom tenant or business connection IDs).

H. Bot API Method Calls & File Operations ​

$bot->sendMessage(mixed ...$args)
→mixedDynamic
All Telegram Bot API methods are callable dynamically with full named argument support and automatic contextual parameter injection.
send(Method $method, ?Closure $uploadProgress = null, ?Closure $downloadProgress = null, ?RequestOptions $options = null)
→mixed
Executes an explicit Method instance with optional progress callbacks and per-request timeout/proxy options.
downloadFile(mixed $file, mixed $destination, ?callable $progress = null)
→BooleanResult|Error
Downloads a file from Telegram servers (by file_id, File object, or path) directly to disk or stream with download progress tracking.
parseUpdate(string|array $payload)
→Update
Parses a raw webhook JSON payload string or decoded array into a fully typed Update object.

I. Underlying Subsystems & Dependency Injection ​

$bot->client
→TelegramClientProperty
Returns the pure TelegramClient instance to execute Bot API requests directly, bypassing update processing.
$bot->dispatcher
→UpdateDispatcherProperty
Returns the underlying UpdateDispatcher instance managing handlers and catchers.
$bot->context
→ContextResolverProperty
Returns the ContextResolver instance for registering or inspecting contextual defaults.
setContainer(mixed $container)
→static
Configures a PSR-11 container or callable resolver used for dependency injection in controllers, handlers, and flows.
$bot->container
→mixedProperty Hook
Returns the configured PSR-11 dependency injection container or container resolver.
$bot->flowManager
→FlowManagerProperty Hook
Returns the underlying FlowManager state orchestrator managing storage drivers and transition hooks.
$bot->router
→RouterProperty Hook
Returns the underlying Router instance for custom route group manipulation.
scoped(?Update $update = null)
→staticConcurrency
Spawns an isolated, thread-safe clone of the Telegram bot client with dedicated context for persistent worker engines (FrankenPHP, RoadRunner, Swoole, Octane).

Released under the MIT License.