Alfonso's Website
10 min read time

Sending Notifications on Telegram with Laravel, the Easy Way

In this post, I will show you how to send notifications via Telegram using Laravel in a simple and easy-to-configure way.

Steps to Follow

1. Create Your Bot in Telegram

  1. Start a Conversation with BotFather: Go to Telegram and search for @BotFather.

  2. Create a New Bot: Use the /newbot command and follow the instructions.

    /newbot
    
  3. Assign a Name: Choose a unique name for your bot, such as mysuperbot9000_bot. It must end with _bot.

  4. Get the Token: You will receive a token similar to 1234567890:AAG2eDLduCRjsgHlms1EezWoCqBlpsSJexE. Keep it safe, as you will need it later.

2. Configure Laravel

  1. Install the Required Package: Use Composer to install "Telegram Notifications Channel for Laravel".

    composer require laravel-notification-channels/telegram
    
  2. Configure the Token: Add the received token in the config/services.php file.

    Note: Only follow these first two steps from the repository. The other steps are not necessary for our approach that uses a webhook.

3. Add telegram_user_id to the User

  1. Edit the User Migration or Create Migration: Add the telegram_user_id column to the users table. For example:

    // database/migrations/2014_10_12_000000_create_users_table.php
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            // Rest of the columns…
            $table->string('telegram_user_id')->nullable();
        });
    }
    

4. Create the Controller for the Webhook

  1. Handling Telegram Messages: The controller will process the messages received, extracting the Telegram user ID and associating it with the corresponding user in your system.
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;

class TelegramBotWebhookController extends Controller
{
    public function __invoke(Request $request)
    {
        // Extracts the text of the message received from the Telegram webhook
        $message = Arr::get($request->all(), 'message.text');

        // Extracts the Telegram user ID who sends the message
        $telegramUserId = Arr::get($request->all(), 'message.from.id');

        // Extracts the code after the '/start' command and cleans it of spaces
        $code = trim(Arr::get(explode('/start', $message ?? ''), 1, ''));

        // If there's no code or the Telegram ID is null, end execution
        if (strlen($code) === 0 || $telegramUserId === null) {
            return ['success' => true];
        }

        try {
            // Tries to decrypt the received code
            $decryptedCode = decrypt($code);

            // Checks if the decrypted code complies with the format 'code:{userid}'
            if (preg_match('/^code:(\d+)$/', $decryptedCode, $matches)) {
                // Extracts the user ID from the code
                $userId = $matches[1];

                // Searches for the user in the database using the extracted ID
                $user = User::find($userId);

                // If the user is found, assigns the Telegram ID and saves the change
                if ($user !== null) {
                    $user->telegram_user_id = $telegramUserId;
                    $user->save();
                }
            }
        } catch (DecryptException $e) {
            // In case of an error in decryption, no action is taken
            // (you can add custom error handling here if you wish)
        }

        // Returns a success response
        return ['success' => true];
    }
}

  1. Route in Laravel: Add a route for the webhook in routes/web.php.
use App\Http\Controllers\TelegramBotWebhookController;
// ...rest of the routes
Route::post('telegram/webhook', TelegramBotWebhookController::class)->name('telegram.webhook');
  1. Exclude from CSRF: In app/Http/Middleware/VerifyCsrfToken.php, add the webhook route to the exceptions.
class VerifyCsrfToken extends Middleware
{
    protected $except = [
        // Add this:
        'telegram/webhook',
    ];
}

5. Configure the Webhook in Telegram

  1. Create Command in Laravel: Create a command that sets up the webhook for

your Telegram bot.

<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use NotificationChannels\Telegram\Telegram;

class ConfigureTelegramWebhoook extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'notifications:set-telegram-webhoook';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Set the Telegram webhook for the bot';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $telegram = app(Telegram::class);

        // The `Telegram` class doesn't have a method to set the webhook so we will just
        // use it to get the api url and the token
        $apiUri = sprintf('%s/bot%s/%s', $telegram->getApiBaseUri(), $telegram->getToken(), 'setWebhook');

        Http::post($apiUri, [
            'url' => route('telegram.webhook'),
        ]);

        $this->info(sprintf('Telegram webhook configured to %s !', route('telegram.webhook')));
    }
}

Note: Make sure the webhook route is publicly accessible. If you're working locally, tools like expose can be helpful.

  1. Run the command you just created php artisan notifications:set-telegram-webhoook

  2. If everything works correctly, you should be able to see that the telegram_user_id is correctly assigned in your database.

6. Test the Webhook

  1. Generate Encrypted Code: Use php artisan tinker to generate an encrypted code that associates a user ID with your bot (in a real application you would probably generate this code and give it to the user to copy).
encrypt('code:1') // Replace '1' with the desired user ID
  1. Send Message to the Bot: Use the generated code to send a message to your bot in the format /start {encrypted_code}.

Example:

start eyJpdiI6Im1iZzNVZkxUTlMxUGVESlNmdkE0bFE9PSIsInZhbHVlIjoiSDBoVytqOWxuZUNvZjJzaEZEY3paRjJGcmxNYkF2a2x5Q0tteW9vejJ1OD0iLCJtYWMiOiI4ZDU3Mzg0OGQ0YmMwOTM3MzMxMTI1Y2E1OGI2ODFlNTJlM2E0NjdmMzFlMjAwMGVlMDVkZmM5ZDZmYTVhZTJkIiwidGFnIjoiIn0=

7. Send a Test Notification

  1. Create a Notification: Use the following example notification to test that you receive messages.
<?php

declare(strict_types=1);

namespace App\Notifications;

use App\Enums\NotificationChannelEnum;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use NotificationChannels\Telegram\TelegramMessage;

class TestNotification extends Notification implements ShouldQueue
{
    use Queueable;


    /**
     * Get the notification's delivery channels.
     *
     * @return array<int, string>
     */
    public function via(User $notifiable): array
    {
        return ['telegram'];

    }

    public function toTelegram(User $notifiable)
    {
        // Content with markdown formatting
        $content = sprintf("*%s*\n\n%s", 'Test notification!', 'If you see this message, it means that your notification was sent successfully.');

        return TelegramMessage::create()
            ->to($notifiable->telegram_user_id)
            ->content($content);
    }
}

  1. Test the Notification: In the Laravel console, send a test notification.

php artisan tinker

User::find(1)->notifyNow(new App\Notifications\TestNotification())

You should receive a notification from your bot on Telegram.