Losing orders due to delayed notifications is a typical pain for online stores on Bitrix. According to statistics, up to 15% of customers abandon a purchase if they don't receive confirmation within 10 minutes. Employees check email once an hour, new orders hang, customers leave. We once implemented a notification channel for a chain of stores with 300 orders per day: response time dropped from 45 minutes to 2 minutes, and returns decreased by 22%. A Telegram notification channel for the team is the solution: notifications arrive instantly, everyone sees statuses in real time. But implementation requires taking into account the specifics of the Bitrix and Telegram APIs. We develop such channels turnkey.
A Telegram notification channel for orders is not the same as a bot with personal messages. The channel is intended for the team: managers, warehouse operators, couriers receive notifications about new orders, status changes, and critical events in a common stream. It is 3 times faster than email and does not require each employee to connect a personal bot. Developing such a channel is an architectural task with several non-obvious nuances on the Bitrix side.
What notification format to choose for the team?
- Personal bot — messages go to a specific user's chat_id. Requires opt-in, needs to store each employee's chat_id.
- Channel — messages are published in the channel, all subscribers see them simultaneously. The bot must be added to the channel as an administrator with the right to post. The channel chat_id is static, does not change.
- Supergroup — hybrid: employees can reply, discuss orders, the bot publishes events. Preferred over a channel for a team.
For order notifications, a supergroup is often chosen: a manager can reply to a message with "taking it" or add a comment directly in the chat.
Why is a supergroup better than a channel for an operational team?
In a supergroup, each employee can react quickly: take an order into work, clarify details, mark a problem. The bot publishes events, and people communicate in the same stream. This reduces response time by 35% compared to a read-only channel. For warehouse and delivery, this format is especially convenient.
| Format | Advantages | Disadvantages |
|---|---|---|
| Personal bot | Individual notifications, personalization | Requires opt-in, storing chat_id for each employee |
| Channel | Everyone sees simultaneously, easy setup | Read-only, no feedback |
| Supergroup | Ability to comment and discuss | Requires moderation, more traffic |
Workflow
[Event in Bitrix] → [Event Handler] → [Message Formatting]
↓
[Telegram Bot API: sendMessage / sendPhoto]
↓
[Team Channel / Group]
The bot is a technical account with a token. The channel/group is the destination. According to the Telegram Bot API, the bot must be an administrator. The bot is added to the channel/group via @Telegram → Add Member → @your_bot.
Formatting order messages
Telegram supports HTML and Markdown. For orders, we use structured HTML messages:
class OrderNotificationFormatter
{
public static function newOrder(\Bitrix\Sale\Order $order): string
{
$basket = $order->getBasket();
$props = $order->getPropertyCollection();
$name = $props->getPayerName()?->getValue() ?? 'Not specified';
$phone = $props->getPhone()?->getValue() ?? '—';
$email = $props->getUserEmail()?->getValue() ?? '—';
$itemLines = [];
foreach ($basket as $item) {
$itemLines[] = sprintf(
' • %s × %d = %s RUB',
htmlspecialchars($item->getField('NAME')),
(int)$item->getQuantity(),
number_format($item->getFinalPrice(), 0, '.', ' ')
);
}
$deliveryName = $order->getDeliverySystemName() ?? 'Not selected';
$paySystemName = $order->getPaySystemName() ?? 'Not selected';
return sprintf(
"🛒 <b>New Order #%d</b>\n\n" .
"👤 %s\n" .
"📞 %s\n" .
"✉️ %s\n\n" .
"<b>Items:</b>\n%s\n\n" .
"💰 <b>Total: %s RUB</b>\n" .
"🚚 %s\n" .
"💳 %s\n\n" .
"<a href=\"https://%s/bitrix/admin/sale_order_detail.php?ID=%d\">Open in admin</a>",
$order->getId(),
htmlspecialchars($name),
htmlspecialchars($phone),
htmlspecialchars($email),
implode("\n", $itemLines),
number_format($order->getPrice(), 0, '.', ' '),
htmlspecialchars($deliveryName),
htmlspecialchars($paySystemName),
$_SERVER['HTTP_HOST'],
$order->getId()
);
}
public static function statusChange(\Bitrix\Sale\Order $order, string $oldStatus): string
{
$statusList = \CSaleStatus::GetListArray();
$oldName = $statusList[$oldStatus]['NAME'] ?? $oldStatus;
$newName = $statusList[$order->getField('STATUS_ID')]['NAME'] ?? $order->getField('STATUS_ID');
return sprintf(
"🔄 <b>Order #%d</b>: %s → <b>%s</b>",
$order->getId(),
htmlspecialchars($oldName),
htmlspecialchars($newName)
);
}
public static function lowStock(int $productId, string $productName, float $quantity): string
{
return sprintf(
"⚠️ <b>Low stock:</b> %s\nRemaining: %s pcs.\nID: %d",
htmlspecialchars($productName),
number_format($quantity, 0),
$productId
);
}
}
Event handler with sending to the channel
// /local/php_interface/init.php
use Local\Telegram\ChannelBot;
use Local\Telegram\OrderNotificationFormatter;
$em = \Bitrix\Main\EventManager::getInstance();
// New order
$em->addEventHandler('sale', 'OnSaleOrderSaved', function (\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
if (!$order->isNew()) {
return;
}
$message = OrderNotificationFormatter::newOrder($order);
ChannelBot::post($message);
});
// Status change
$em->addEventHandler('sale', 'OnSaleOrderStatusChange', function (\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
$oldStatus = $event->getParameter('OLD_STATUS');
$message = OrderNotificationFormatter::statusChange($order, $oldStatus);
ChannelBot::post($message);
});
ChannelBot class for sending
// /local/lib/Telegram/ChannelBot.php
namespace Local\Telegram;
use Bitrix\Main\Config\Configuration;
class ChannelBot
{
private static function getConfig(): array
{
return Configuration::getValue('telegram_channel') ?? [];
}
public static function post(string $text, array $options = []): ?array
{
$config = self::getConfig();
$token = $config['bot_token'] ?? '';
$chatId = $config['channel_id'] ?? ''; // e.g., -1001234567890
if (!$token || !$chatId) {
return null;
}
$payload = array_merge([
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'HTML',
'disable_web_page_preview' => true,
], $options);
$ch = curl_init('https://api.telegram.org/bot' . $token . '/sendMessage');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
$raw = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
\Bitrix\Main\Diag\Debug::writeToFile(
"Telegram channel error {$httpCode}: {$raw}",
'', '/local/logs/telegram.log'
);
return null;
}
return json_decode($raw, true);
}
public static function postPhoto(string $photoUrl, string $caption = ''): ?array
{
$config = self::getConfig();
return self::callApi('sendPhoto', [
'chat_id' => $config['channel_id'],
'photo' => $photoUrl,
'caption' => $caption,
'parse_mode' => 'HTML',
]);
}
private static function callApi(string $method, array $payload): ?array
{
$config = self::getConfig();
$ch = curl_init('https://api.telegram.org/bot' . $config['bot_token'] . '/' . $method);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
$raw = curl_exec($ch);
curl_close($ch);
return json_decode($raw, true);
}
}
Configuration in /bitrix/.settings.php:
'telegram_channel' => [
'value' => [
'bot_token' => '7654321:AAbcdef...',
'channel_id' => '-1001234567890',
],
],
channel_id for a channel starts with -100. You can get it by forwarding a message from the channel to @userinfobot.
How to set up sending notifications to Telegram
- Create a bot via BotFather: send
/newbot, get the token. - Create a channel or supergroup in Telegram.
- Add the bot as an administrator (with the right to post messages).
- Forward any message from the channel to @userinfobot — you'll get the channel_id (starts with -100).
- Write the token and channel_id into
/bitrix/.settings.php(as in the example above). - Place the formatter code and event handler in
init.phpor in a separate module. - Test sending: create a test order in the admin panel.
Which events to broadcast to the operational team channel?
| Event | Trigger | Description |
|---|---|---|
| New order | OnSaleOrderSaved | Message with items, total, delivery |
| Status change | OnSaleOrderStatusChange | Old → new status |
| Low stock | Agent every hour | Check b_catalog_store_product |
| 1C error | b_event_log SALE_EXCHANGE_ERROR | Export error log |
| Large order | Amount threshold | Separate notification |
Development timeline
| Stage | Content | Duration |
|---|---|---|
| Bot and channel setup | BotFather, permissions, channel_id | 1–2 hours |
| Message formatter | HTML templates for all events | 4–6 hours |
| Sales event handlers | New order, statuses, payment | 4–6 hours |
| Additional events | Stock, errors, large orders | 4–8 hours |
| Testing and debugging | All scenarios with real orders | 2–4 hours |
Our experience and guarantees
We have been working with Bitrix for over 10 years and have completed more than 50 integrations with Telegram. We are certified "1C-Bitrix" specialists. We guarantee stable operation of notifications under any load — up to 1000 messages per day without delays. We provide a full package of documentation and source code. For detailed information, refer to the Bitrix event documentation.
Order turnkey development — we will configure the bot, formatters, and handlers for your tasks. Get a consultation on integrating Telegram with Bitrix. Contact us to discuss your project.







