Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Essence Laravel Package

telegram-bot-essentials/essence

Essence provides core building blocks for Telegram bots in Laravel and PHP applications. It streamlines bot setup, command and message handling, and common messaging tasks with a concise, essentials-focused API designed to keep integrations lean and maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

Essence is a Laravel-first package for Telegram bot plumbing: fluent senders, update handling (webhook or polling), keyboards, and — per the package description — command/reply-key/callback-query buses, conversational state, and per-bot tenancy. Treat the first day as a spike, not an integration: you are validating that the public API matches what the README claims before you let it touch a real bot.

1. Install pinned, not loose. The package is pre-1.0 and the latest tag is a beta. Pin the exact version in composer.json:

composer require telegram-bot-essentials/essence:0.18.1

Only move to 0.19.0-beta.1 after you have read the diff between the two tags — the release note for that version is a bare changelog link, so the changelog is the primary source of truth, not the description.

2. Configure and publish.

php artisan vendor:publish --tag=essence-config   # confirm the exact tag in the README

Set the bot token(s) in .env, and check the published config/essence.php for: update delivery mode (webhook vs polling), any driver/queue bindings, and — since per-bot tenancy is advertised — how bots are declared and resolved.

3. Decide delivery mode immediately. Production: a webhook route behind your normal HTTPS + middleware stack. Local: polling via the package's artisan command so you don't need a tunnel for every test.

# webhook
curl "https://api.telegram.org/bot${TOKEN}/setWebhook?url=https://app.test/telegram/webhook&secret_token=${SECRET}"

4. First use case: /start + echo. The fastest end-to-end validation of token → update routing → reply is a single command handler:

Essence::onMessage()
    ->command('start')
    ->reply('Welcome!');

Essence::onMessage()
    ->hear('hello')
    ->reply('Hi there 👋');

Register it in a service provider (not in a closure pulled in by a route file — see Gotchas) and confirm one round trip works before adding keyboards or state.

5. Where to look first, in order:

  • config/essence.php — token(s), delivery mode, tenancy model, queue settings.
  • The facade/entry class — the onMessage() / onCallbackQuery() / onInlineQuery() surface and what each chainable step returns.
  • The repo's tests — with 0 stars and no prose release notes, the test suite is your most reliable documentation of intended behaviour, especially around tenancy and conversational state.

If per-bot tenancy is a hard requirement, prove it on day one with two tokens and two handlers before building anything else on top of it. It is the easiest feature to discover is half-finished after you have written twenty handlers.

Implementation Patterns

One handler file per feature area. Do not grow a single 400-line provider. Split by domain — OnboardingHandlers.php, SupportHandlers.php, AdminHandlers.php — and load them from one BotServiceProvider. Ordering is load-bearing: register specific command()/hear() matchers before catch-all text handlers, because the first match typically wins.

Split by update type, deliberately. onMessage() for text, onCallbackQuery() for inline button presses, onInlineQuery() for inline mode, onChannelPost() / onEditedMessage() where relevant. Registering the same intent across entry points is normal and expected — resist the urge to funnel everything through onMessage() and switch on payload shape inside.

Answer callback queries first, then work. Telegram gives you a short window to acknowledge a button press before the client spinner hangs. Pattern:

Essence::onCallbackQuery()
    ->hear('order:confirm')
    ->answer()              // immediate ack
    ->then(fn ($q) => dispatch(new ConfirmOrder($q->data)));

Do the slow thing (DB write, queue push, external API) after the ack, never before.

Keysboards via the builders, never hand-rolled arrays. The classic production bug in every Telegram integration is reply_markup being sent as a JSON string where an object was expected, or vice versa. Use the package's keyboard helpers so callback data stays consistent, and centralise callback-data formats (e.g. domain:action:id) in one class so parsing is never duplicated.

Conversational state: short-lived only. Whatever "remember" helper the package exposes, treat it as a cache. For anything load-bearing — multi-step forms, onboarding progress, cart contents — persist in your own table keyed by (chat_id, from.id) and keep the package state for the current turn. This matters double for per-bot tenancy: your state key must include the bot/tenant identifier, or two bots sharing a user will collide.

Per-bot tenancy: resolve once, at the edge. Register a middleware or early filter that maps the incoming update to a bot record (by token hash, path segment, or webhook secret) and binds it into the container. Every downstream handler, queue job, and outbound send should read the current bot from that binding rather than from config('essence.token'). This is the single highest-leverage design decision in a multi-bot app — get it right before the first handler.

// resolve tenant from webhook route/secret, then:
app()->instance('essence.bot', $bot);

Queue anything non-interactive. Telegram caps roughly 30 messages/sec per bot and ~1/sec per chat. Broadcasts, notifications, and fan-outs belong in a queued job, chunked with small sleeps. Interactive replies stay synchronous. If you queue, carry the tenant context into the job explicitly — do not rely on the container binding surviving the worker.

Filter early. Ignore chats you don't own, allowlist from.id where appropriate, and short-circuit before handlers run. The fluent API tempts you into one enormous chained expression; instead keep each handler a small named method so you can unit-test it.

Test with synthetic updates, assert on replies. Dispatch fabricated update payloads through the entry point and assert on what the bot chose to send, mocking the transport rather than the handler logic. With a 0-star package and an undocumented beta, your test suite is also your upgrade safety net — you will need it when 0.19.0 stable lands.

Wrap it. Put a thin internal interface in front of Essence (BotMessenger, BotRouter) even if it feels like ceremony on day one. Given the version churn and the fact that the advertised feature set (buses, tenancy, state) is not clearly documented in the release notes, you want the option to swap implementations without a codebase-wide rewrite.

Gotchas and Tips

Pre-1.0 means minor releases can break you. 0.18.1 → 0.19.0-beta.1 is a minor bump and may rename methods, change chainable return types, or reorder handler precedence. Pin exact versions, read the compare diff before bumping, and never run composer update on this package casually.

Description and documentation disagree — trust neither blindly. The description advertises command/reply-key/callback-query buses, conversational state, and per-bot tenancy; the available usage material shows a fluent facade. Verify which API actually exists in your tag before designing around the marketing copy. Anything you can't find in the source, assume isn't there.

Beta in staging, never straight to production. Install 0.19.0-beta.1 against a throwaway bot first and exercise every entry point — commands, callback queries, inline queries, edited messages. Keep the previous lock entry noted so rollback is one command.

Route caching will silently eat closure-based handlers. php artisan route:cache drops closures. If your handlers are registered that way, they vanish in production while working fine locally. Prefer class-based registration or an explicit handler file required by a service provider.

Set and validate the webhook secret. Always pass secret_token to setWebhook and reject requests missing a matching X-Telegram-Bot-Api-Secret-Token header in middleware. An unauthenticated webhook endpoint accepts spoofed updates from anyone.

Handlers must be idempotent. Telegram retries failed deliveries. Dedupe on update_id (a unique index plus an insertOrIgnore is enough), or a slow handler will produce duplicate messages and duplicate side effects.

Rate limits show up as silent backoff loops. Log every 429 and 5xx from the Bot API. A polling worker that quietly retries forever looks healthy in ps and dead in the chat.

Polling is a long-running PHP process. Opcache, memory, and DB connections drift. Run it under supervisor with periodic restarts, and don't debug it by leaving it in a for loop in your terminal.

Multi-bot token leakage. Tokens end up in URLs (/bot<TOKEN>/...), so they leak into HTTP client logs, exception traces, and Telescope. Redact aggressively; use per-bot secret tokens rather than sharing one; and confirm config caching (php artisan config:cache) behaves correctly when bots are declared dynamically rather than in the config file.

Debug the update, not the transport. Log the raw payload before any parsing, and log the outgoing API response body on failure (Telegram returns useful description fields on 400s). Most "handler didn't fire" bugs are update-type mismatches or handler ordering; most "message not delivered" bugs are malformed chat_id or reply_markup shape.

Extension points are the sanctioned seams: the config file (defaults, driver selection), container bindings for custom transport/middleware, and any events the package fires around update receipt. Use those for cross-cutting behaviour rather than monkey-patching the facade — the latter breaks on every minor bump.

Weigh the vendor risk explicitly. 0 stars, no SLA, no prose release notes, and a beta tag mean you own the operational risk. Budget for reading source and diffing releases yourself, and keep the internal adapter boundary in place until a stable release with real documentation exists.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect