unreal4u/telegram-api
A comprehensive PHP client for the Telegram Bot API that simplifies sending messages, media, locations, and inline keyboards, handling updates and webhooks, and building interactive bots with a clean, well-documented object-oriented interface.
composer require unreal4u/telegram-api. The package targets PHP 7.1+ and pulls in ReactPHP, so async support is present even if you only use the synchronous-looking calls.TG_BOT_TOKEN). Never commit it; the package takes it as a constructor argument.TgLog and pass it a GetMe method object through performApiRequest(). If that round-trips, your token, network, and TLS setup are fine.use unreal4u\TelegramAPI\TgLog;
use unreal4u\TelegramAPI\Telegram\Methods\SendMessage;
$tgLog = new TgLog(getenv('TG_BOT_TOKEN'));
$msg = new SendMessage();
$msg->chat_id = '<chat id>'; // integer, or '@publicchannel'
$msg->text = 'Hello from PHP';
$tgLog->performApiRequest($msg);
src/Telegram/Methods/ — one class per Bot API method. Public property names mirror Telegram's parameter names, so this directory is effectively your offline API reference.src/Telegram/Types/ — nested objects (InputFile, keyboards, Message, etc.).src/TgLog.php — the transport: token handling, loop/client injection, request dispatch, response hydration.src/Abstracts/TelegramApi.php and bin/telegram-bot.php — the opinionated polling/action runner.examples/ and tests/ — closest thing to documentation for the runner.getUpdates loop and TgLog (learn the method-object mapping), then move to the action runner only if you want its polling framework.performApiRequest(). This gives strong IDE completion but no client-side validation — Telegram silently drops unknown/typo'd parameters and only tells you via a 400, so copy parameter names from src/Telegram/Methods/ rather than from memory.TgLog as an injectable service. It works in any context (Laravel command, queue job, webhook controller). Register it as a singleton with the token from config/env, and pass an optional PSR logger so you can see request/response payloads at debug level.performApiRequest() returns a ReactPHP promise. For nontrivial flows, create the loop explicitly, pass it into TgLog, chain ->then($onOk, $onError), and call $loop->run(). There is no await; sequence dependent calls by chaining or by a recursive "send next on resolve" function.->then() with the chat id in scope for per-recipient error handling, and let the loop drain. Wrap the sender in a token-bucket or delayed queue — the package does not rate-limit for you.unreal4u\TelegramAPI\Abstracts\TelegramApi, annotate public methods with @Action, build method objects inside them, use $this->chat_id, and yield each method the runner should execute. Register classes in the config array and launch ./bin/telegram-bot.php --config=config.php --action=YourAction. It polls getUpdates and dispatches; it is deliberately small and single-purpose.SetWebhook method object, decode php://input, and call TgLog directly. Respond 200 first, then enqueue actual work — Telegram retries slow/failed webhooks.Types\InputFile with an absolute path (or resource) on SendDocument/SendPhoto/etc.; the package switches that request to multipart. After the first upload, reuse the returned file_id instead of re-uploading.TgLog if your version exposes it, or (safer) put a thin TelegramSender interface around TgLog and mock that. Assert on populated method objects before dispatch; assert on typed responses via fixtures.TgLog in a service provider; dispatch sends from queued jobs so HTTP requests never block on Telegram latency; centralize retry/backoff in your own sender class that wraps performApiRequest().sendMessage fields, business/boost updates, webhook secret_token, etc.), and PHP 8.2+ dynamic-property deprecations are likely. Pin the version, audit transitive deps, and plan to fork or migrate. For greenfield work, weigh actively maintained alternatives or a thin Guzzle/HTTP wrapper.$loop->run() or returned before the loop drained. Conversely, calling $loop->run() when a loop is already running throws. Don't rely on the library auto-running a loop for you in production paths — own the loop explicitly.TgLog directly rather than patching around it.@name works only for public channels. Get the id from an incoming update — the bot's own user id is not a valid destination for its messages.ok: false becomes a rejected promise/exception, not an HTTP error. Always attach a rejection handler and branch on the Telegram error_code: 400 bad request (often a dropped parameter name), 403 bot blocked, 429 rate limited with retry_after — honor it with exponential backoff.file_id reuse.@Action is Doctrine annotation syntax, not PHP 8 attributes. Keep the docblock exact and ensure the annotation reader/autoloader is configured per the docs, or actions are silently ignored.GetMe; (2) json_encode the method object before dispatch to confirm property names; (3) log the full rejection payload, not just the message; (4) test in a private chat with the bot; (5) on 400, re-check parameter spelling against current Bot API docs — unknown keys are discarded without complaint.TgLog to add retry/rate-limiting; add a class under Telegram/Methods for an endpoint the package predates (wire up the endpoint path, parameters, and a response class); wrap performApiRequest() in your own sender to centralize logging, metrics, and backoff.getUpdates with timeout > 0) needs the underlying HTTP client timeout raised too, or the connection is cut before Telegram replies. Config paths are resolved relative to the working directory — matters under cron/systemd.How can I help you explore Laravel packages today?