Register Webhooks
To receive Telegram updates through a webhook, register a public https URL for a specific bot. For the fast onboarding path, see the quickstart webhook step; this page covers registration parameters and diagnostics in more detail. For symptom-based first-bot diagnostics, see Troubleshooting Telegraph onboarding.
Public URL and local tunnel
Telegram must be able to reach your application from the public internet. In production this is usually your application domain; in local development it is a temporary https tunnel:
ngrok http 8000
Copy the public tunnel URL and configure one of these values:
APP_URL=https://example.ngrok-free.app TELEGRAM_WEBHOOK_DOMAIN=https://example.ngrok-free.app
TELEGRAM_WEBHOOK_DOMAIN sets telegraph.webhook.domain and is used when registering the webhook instead of the domain from APP_URL. This is useful when the rest of the application still uses a local APP_URL, but Telegram needs a public route.
If you use php artisan config:cache, clear cached config after changing .env:
php artisan config:clear
Route URL
Telegraph registers a Laravel route named telegraph.webhook. The default path is:
/telegraph/{token}/webhook
With the default config, the full URL looks like this:
https://example.ngrok-free.app/telegraph/{token}/webhook
You can change the path through TELEGRAPH_WEBHOOK_URL (telegraph.webhook.url) or disable the route by setting the config value to null:
TELEGRAPH_WEBHOOK_URL=/telegram/{token}/webhook
If the route changes, verify that middleware and the reverse proxy allow POST requests to the new URL.
Secret token
The Telegram Bot API lets you pass a secret_token when registering a webhook. Telegram sends that value in the X-Telegram-Bot-Api-Secret-Token header on later webhook requests.
Store the value in .env and do not publish it in issues, logs, or screenshots:
TELEGRAPH_WEBHOOK_SECRET=your-secret-token
For CLI registration, pass the secret explicitly:
php artisan telegraph:set-webhook {bot_id} --secret="${TELEGRAPH_WEBHOOK_SECRET}"
For programmatic registration, pass secretToken:
/** @var DefStudio\Telegraph\Models\TelegraphBot $telegraphBot */ $telegraphBot->registerWebhook( secretToken: config('telegraph.webhook.secret'), )->send();
NoteTelegraph sends
secret_tokento Telegram during registration. If your application must enforce inbound validation of theX-Telegram-Bot-Api-Secret-Tokenheader, add that check to middleware fromtelegraph.webhook.middlewareor to your own request handling layer.
Artisan command
Register a webhook with:
php artisan telegraph:set-webhook {bot_id}
can be omitted when the system has only one bot. Available options:
php artisan telegraph:set-webhook {bot_id} \
--drop-pending-updates \
--max-connections=100 \
--secret=your-secret-token
--drop-pending-updatesremoves pending updates on Telegram when changing the webhook.--max-connectionssets the maximum allowed simultaneous connections. The default comes fromtelegraph.webhook.max_connections.--secretpasses Telegram thesecret_token.
Allowed updates
telegraph.webhook.allowed_updates can be set in config when the bot should receive only some update types. A null value keeps Telegram's default behavior: all update types except some opt-in events such as chat_member, message_reaction, and message_reaction_count.
Example config:
'webhook' => [ 'allowed_updates' => ['message', 'callback_query'], ],
Programmatic registration
If the application has its own bot management logic, register the webhook through TelegraphBot:
/** @var DefStudio\Telegraph\Models\TelegraphBot $telegraphBot */ $telegraphBot->registerWebhook( dropPendingUpdates: true, maxConnections: 100, secretToken: 'your-secret-token', )->send();
For the method signature, see the TelegraphBot documentation.
WarningManual updates polling is not available while a bot has a configured webhook. First remove the webhook through the unregisterWebhook method.
Check with the debug command
After registration, check the webhook state on Telegram:
php artisan telegraph:debug-webhook {bot_id}
The command shows Telegram webhook diagnostics such as url, pending_update_count, last_error_date, last_error_message, max_connections, and allowed_updates when Telegram returns those fields. This is Telegram delivery diagnostics, not a dump of the incoming Laravel request.
For runtime diagnostics, use:
php artisan telegraph:debug-webhook {bot_id}for the webhook state in Telegram.storage/logs/laravel.logfor handler, middleware, and application code errors.- The tunnel inspector (
ngrokweb UI or similar) to check incomingPOSTrequests.
Do not paste real bot tokens, webhook secrets, Telegram headers, or full user payloads into public issues or shared logs.
Troubleshooting local development
The full onboarding troubleshooting guide is available in Troubleshooting Telegraph onboarding. This section keeps the webhook-specific checks short.
Telegram rejects the URL
Make sure the webhook URL starts with https://. If the route does not use TELEGRAM_WEBHOOK_DOMAIN, Laravel must generate a secure URL from APP_URL.
Tunnel URL changed after restart
Free tunnel URLs often change after restart. Update APP_URL or TELEGRAM_WEBHOOK_DOMAIN, run php artisan config:clear, then run telegraph:set-webhook again.
debug-webhook shows an old URL
The config cache probably still contains old env values, or the webhook was not registered again after changing the tunnel. Run:
php artisan config:clear
php artisan telegraph:set-webhook {bot_id} --secret=your-secret-token
php artisan telegraph:debug-webhook {bot_id}
Route returns 404
Check TELEGRAPH_WEBHOOK_URL and the published config. By default the route should be /telegraph/{token}/webhook; if you override the path, the same path must be registered in Telegram. Also check php artisan route:list in the host application.
Route returns 401 or 403
Check middleware from telegraph.webhook.middleware, CSRF/external access rules, the reverse proxy, and any custom X-Telegram-Bot-Api-Secret-Token validation. The secret in Telegram registration and the expected middleware value must match.
/chatid does not answer in a new chat
By default the webhook handler accepts requests only from known TelegraphChat models and can reject unknown chats. To obtain the first chat_id, use the default handler flow from the overview or configure the unknown-chat security options deliberately.
Pending updates arrive after changing the webhook
If old updates are no longer useful, register the webhook again with --drop-pending-updates:
php artisan telegraph:set-webhook {bot_id} --drop-pending-updates --secret=your-secret-token
If you need to remove the webhook entirely, use telegraph:unset-webhook.