sergix44/nutgram
Nutgram is a modern PHP Telegram bot framework with a Laravel-style API and first-class Laravel integration. Build bots with handlers, middleware, conversations, webhooks, and testable code without boilerplate.
Nutgram is a Telegram Bot API framework with first-class Laravel integration. A typical install looks like:
composer require nutgram/nutgram
php artisan nutgram:install # publishes config/nutgram.php and scaffolding
Then set TELEGRAM_TOKEN in .env. The first place to look is config/nutgram.php — it controls the token, the run mode (polling vs webhook), webhook URL/secret, and the handler/middleware loading paths. Second place is routes/telegram.php, where handlers are registered:
use App\Telegram\Handlers\StartHandler;
$bot->onCommand('start', StartHandler::class);
$bot->onText('hello', fn (Nutgram $bot) => $bot->sendMessage('Hi!'));
A first use case: create a handler with php artisan nutgram:make:handler StartHandler, register it on /start, then run php artisan nutgram:run locally (long polling, no public URL needed). Once deployed behind HTTPS, switch to webhook mode with php artisan nutgram:hook:set.
Note on 4.50.3: this is a patch release fixing Bot API type mismatches around media, ephemeral edits, entities and rich text. There are no migration steps, but if you rely on the generated IDE/type helpers (see below), regenerate them after upgrading.
app/Telegram/Handlers, keep routes/telegram.php as a thin routing table, and inject Nutgram into __invoke(Nutgram $bot, ...). This keeps handlers testable and queueable.php artisan nutgram:make:command, nutgram:make:conversation) and use $bot->onCommand('start', ...). Conversations are the idiomatic way to model multi-step forms instead of stashing state in the cache yourself.$bot->middleware(EnsureUserIsKnown::class) for user lookup/registration, rate limiting, or logging. Middleware runs per-update, which is the right granularity for idempotency keys.Nutgram\Laravel\Facades\Nutgram::sendMessage(...) is convenient for sending from anywhere (controllers, jobs, console commands); prefer constructor injection of the client in services you unit test.Nutgram::fake() in feature tests, register the same routes file, ->hearText('/start')->reply() and assert outgoing calls. This is the fastest way to keep handler coverage without a live bot.nutgram:run under a process supervisor. Production: nutgram:hook:set (and nutgram:hook:remove for rollbacks), keeping mode consistent in config per environment.php artisan nutgram:ide:generate so $bot->sendMessage() arguments and update payloads autocomplete. Treat the generated directory as build output: regenerate after every composer update.TelegramUser model keyed by from.id for anything stateful.composer update nutgram/nutgram, then php artisan nutgram:ide:generate (and clear bootstrap/cache / opcache). If you had written manual @param docblocks or subclasses mirroring the old shapes, re-check them — the types moved, not the wire format.php artisan nutgram:cache:clear after adding or renaming handlers — otherwise new routes silently don't fire. This is the most common "my handler isn't called" cause after a deploy.message.text using MessageEntity offsets/lengths, don't use plain substr on multibyte strings. The rich-text/entity fixes in this release are a good reminder to centralize that logic in one helper.sendMediaGroup returns an array of messages, not one; InputMedia captions are limited and cannot be set on every item. Validate file sizes and MIME types locally before uploading, or you'll burn rate limit on guaranteed failures.api_url or a proxy, it may not implement the newer endpoints. Mismatched types here typically surface as "unknown method" or malformed payload errors rather than PHP exceptions.retry_after; for bulk sends, stagger via queued jobs with a small delay rather than looping synchronously.file_ids per (chat, purpose) instead of re-uploading the same asset.nutgram:run against a bot that still has a webhook set yields no updates. Clear it with nutgram:hook:remove before polling locally.webhook.secret_token, verify the X-Telegram-Bot-Api-Secret-Token header; also exclude the webhook route from CSRF and session middleware, or updates will 419.APP_DEBUG; most "type mismatch"/"wrong payload" issues are visible immediately in the raw update JSON.api_url for local Bot API servers, additional middleware for cross-cutting auth, and Laravel events fired from handlers for domain decoupling are the safe seams — avoid patching vendor classes for type issues, since patch releases like this one will move them.How can I help you explore Laravel packages today?