Skip to content

Instantly share code, notes, and snippets.

@saeedvir
Last active October 16, 2025 05:48
Show Gist options
  • Select an option

  • Save saeedvir/b62b48712f95b3e4d10e2ea7537cdfd2 to your computer and use it in GitHub Desktop.

Select an option

Save saeedvir/b62b48712f95b3e4d10e2ea7537cdfd2 to your computer and use it in GitHub Desktop.
Laravel Send Notification to Telegram or Bale Messenger
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
/**
* By saeedvir: https://github.com/saeedvir
* Messenger notifier for Telegram & Bale.
*
* 1) Create the Telegram/bale bot
Open Telegram and start a chat with @BotFather.
Send /newbot and follow prompts (name, username).
BotFather will return a Bot Token like 123456:ABC-DEF.... Keep it secret — store it in an env file.
* 2) Create the channel and add the bot
Create a Telegram/Bale channel (private or public).
Add your bot as an administrator of the channel and give it permission to post messages.
* 3) Get the channel chat_id
If the channel is public and has a username @mychannel — you can use @mychannel as the chat_id.
If the channel is private (no username), do this:
Post any message in the channel (you or any admin).
Forward that message to your bot (open message → forward → pick your bot).
Call the Bot API getUpdates to see the forwarded message and retrieve forward_from_chat.id.
Example (paste in browser):
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates
or
https://tapi.bale.ai/bot<YOUR_TOKEN>/getUpdates
In the JSON you’ll see something like "forward_from_chat": {"id": -1001234567890, ...} — that -1001234567890 is the channel chat_id.
(Alternative: forward to any bot that shows raw updates, or use @RawDataBot — but the getUpdates method above works without third-party tools.)
*4) Create a new instance of MessengerNotifier
$notifier = new MessengerNotifier(null, 'bale');
$ok = $notifier->info("<b>New Order Received!</b>\nOrder ID: 12345");
if ($ok) {
$notifier->sendDocument(storage_path('logs/laravel.log'), 'Laravel Log Snapshot');
return "Sent to messenger!";
} else {
return "Failed to send.";
}
**/
class MessengerNotifier
{
protected string $token;
protected string|int $chatId;
protected string $baseUrl;
protected string $messenger;
/**
* Create a new instance of the messenger notifier.
*
* @param string|null $chatId The chat ID to use for sending messages. If null, the value from the config will be used.
* @param string $messenger The messenger to use. Can be either 'telegram' or 'bale'.
* @throws \InvalidArgumentException
*/
public function __construct(?string $chatId = null, string $messenger = 'telegram')
{
$this->messenger = strtolower($messenger);
if ($this->messenger === 'telegram') {
$this->token = config('services.telegram.bot_token', env('TELEGRAM_BOT_TOKEN'));
$this->chatId = $chatId ?? config('services.telegram.chat_id', env('TELEGRAM_CHANNEL_ID'));
$this->baseUrl = "https://api.telegram.org/bot{$this->token}";
} elseif ($this->messenger === 'bale') {
$this->token = config('services.bale.bot_token', env('BALE_BOT_TOKEN'));
$this->chatId = $chatId ?? config('services.bale.chat_id', env('BALE_CHANNEL_ID'));
$this->baseUrl = "https://tapi.bale.ai/bot{$this->token}";
} else {
throw new \InvalidArgumentException("Unsupported messenger: {$this->messenger}");
}
}
/**
* Send a message to the specified chat.
*
* @param string $message
* @param string $parseMode
* @param string|null $chatId
* @return bool
* @throws \Throwable
*/
public function send(string $message, string $parseMode = 'HTML', ?string $chatId = null): bool
{
$url = "{$this->baseUrl}/sendMessage";
$data = [
'chat_id' => $chatId ?? $this->chatId,
'text' => $message,
'parse_mode' => $parseMode,
'disable_web_page_preview' => true,
];
try {
$response = Http::timeout(10)->post($url, $data);
return $response->successful();
} catch (\Throwable $e) {
Log::error("{$this->messenger} send() failed: " . $e->getMessage(), [
'url' => $url,
'data' => $data,
]);
return false;
}
}
/** severity helpers */
public function info(string $msg): bool
{
return $this->send("ℹ️ <b>INFO:</b>\n{$msg}");
}
public function warning(string $msg): bool
{
return $this->send("⚠️ <b>WARNING:</b>\n{$msg}");
}
public function error(string $msg, \Throwable $e = null): bool
{
$extra = $e ? "\n<code>{$e->getFile()}:{$e->getLine()}</code>" : '';
return $this->send("❌ <b>ERROR:</b>\n{$msg}{$extra}");
}
/** batch logs */
public function batch(array $messages, string $title = 'Batch Report'): bool
{
$text = "<b>{$title}</b>\n\n" . implode("\n", array_map(fn($m) => "• " . $m, $messages));
return $this->send($text);
}
/** media helpers */
public function sendPhoto(string $filePath, string $caption = ''): bool
{
return $this->sendMedia('sendPhoto', 'photo', $filePath, $caption);
}
public function sendDocument(string $filePath, string $caption = ''): bool
{
return $this->sendMedia('sendDocument', 'document', $filePath, $caption);
}
/**
* Send media (photo or document) to the messenger
*
* @param string $method Telegram method name (sendPhoto or sendDocument)
* @param string $type Media type (photo or document)
* @param string $filePath File path (local or remote URL)
* @param string $caption Caption for the media
*
* @return bool
*/
protected function sendMedia(string $method, string $type, string $filePath, string $caption = ''): bool
{
$url = "{$this->baseUrl}/{$method}";
try {
// Case 1: Remote file (URL)
if (preg_match('/^https?:\/\//i', $filePath)) {
$response = Http::timeout(20)->post($url, [
'chat_id' => $this->chatId,
$type => $filePath, // direct URL
'caption' => $caption,
'parse_mode' => 'HTML',
]);
return $response->successful();
}
// Case 2: Local file (upload)
$client = new \GuzzleHttp\Client(['timeout' => 30]);
$response = $client->post($url, [
'multipart' => [
[
'name' => 'chat_id',
'contents' => $this->chatId,
],
[
'name' => $type, // "photo" or "document"
'contents' => fopen($filePath, 'r'),
'filename' => basename($filePath),
],
[
'name' => 'caption',
'contents' => $caption,
],
],
]);
return $response->getStatusCode() === 200;
} catch (\Throwable $e) {
Log::error("{$this->messenger} {$method} failed: " . $e->getMessage(), [
'url' => $url,
'file' => $filePath,
]);
return false;
}
}
}
@saeedvir
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment