Skip to Content
ProvidersTelegram Bot API

Telegram Bot API

Category: Notification — Messaging
Package: @leadmetrics/provider-telegramTelegramBotProvider
External SDK: axios (Telegram Bot API)


Purpose

Telegram is used for ops and internal alerts — platform administrators and DM agency staff receive system health notifications, error alerts, and escalations via Telegram. Unlike email, SMS, and WhatsApp which serve end clients, Telegram is primarily an internal channel.

Telegram is also available as a notification channel for DM Portal users who prefer it over email for HITL review notifications.

There is a platform default Telegram bot (for ops alerts). Tenants can optionally configure their own bot for their team’s internal notifications.


Key Difference from Other Channels

Telegram uses chat IDs rather than phone numbers or email addresses. Recipients must have already started a conversation with the bot (or been added to a group where the bot is a member) before the bot can send them messages. The defaultChatId in the bot config is the platform ops channel.


Config Structure

Platform default (env vars)

TELEGRAM_BOT_TOKEN=7123456789:AAHxxxxxxxxxxxxxxxxxxxx # Bot token from BotFather TELEGRAM_DEFAULT_CHAT_ID=-1001234567890 # Platform ops channel ID (negative = group/channel)

Tenant config (stored in notification_providers.config, encrypted)

interface TelegramBotConfig { botToken: string; // Bot token from @BotFather defaultChatId?: string | number; // Fallback chat ID when recipient has no specific chatId baseUrl?: string; // Override for self-hosted Bot API server (enterprise only) }

Integration Pattern

Provider class (packages/provider-telegram/src/providers/telegram-bot.ts)

import axios from 'axios'; class TelegramBotProvider implements TelegramProvider { readonly name = 'telegram_bot'; private baseUrl: string; constructor(private cfg: TelegramBotConfig) { this.baseUrl = cfg.baseUrl ?? `https://api.telegram.org/bot${cfg.botToken}`; } async send(message: TelegramMessage): Promise<TelegramSendResult> { const response = await axios.post(`${this.baseUrl}/sendMessage`, { chat_id: message.chatId, text: message.text, parse_mode: message.parseMode ?? 'HTML', disable_web_page_preview: message.disableWebPagePreview ?? false, }); if (!response.data.ok) { throw new Error(`Telegram API error: ${response.data.description}`); } return { messageId: String(response.data.result.message_id), provider: 'telegram_bot', status: 'sent', }; } async verify(): Promise<void> { const response = await axios.get(`${this.baseUrl}/getMe`); if (!response.data.ok) { throw new Error(`Telegram bot verification failed: ${response.data.description}`); } } }

Message formatting

Telegram supports HTML formatting in messages. The platform uses HTML parse mode for rich notification content:

// Example: HITL review notification const text = [ `<b>Review Required</b>`, ``, `Activity: <code>${activityTitle}</code>`, `Client: ${clientName}`, ``, `<a href="${reviewUrl}">Open in DM Portal →</a>`, ].join('\n');

Supported HTML tags: <b>, <i>, <u>, <s>, <code>, <pre>, <a href>.

Chat ID resolution

Chat IDs are stored on the user record in the notification job payload. For ops alerts, the TELEGRAM_DEFAULT_CHAT_ID is used:

// In telegram.handler.ts const chatId = recipient.telegramChatId ?? config.TELEGRAM_DEFAULT_CHAT_ID;

Setting Up a Bot

  1. Message @BotFather on Telegram
  2. Send /newbot and follow prompts
  3. Copy the bot token (format: 1234567890:ABCDEFxxxxxxxx)
  4. Add the bot to the ops group/channel and make it an admin with “Post Messages” permission
  5. Get the chat ID by sending a message and calling getUpdates, or using @userinfobot

For group/channel IDs: they are negative numbers (e.g. -1001234567890). For individual users: positive numbers.


Test Cases

Unit tests (packages/provider-telegram/src/providers/telegram-bot.test.ts)

TestApproach
send() POSTs to sendMessage endpointMock axios.post; assert URL contains /sendMessage
send() sends correct chat_id and textAssert request body
send() uses HTML parse mode by defaultAssert parse_mode === 'HTML'
send() returns messageId as stringMock { ok: true, result: { message_id: 42 } }
send() throws when ok === falseMock { ok: false, description: 'Forbidden' }
send() throws on network errorMock axios.post rejects
verify() calls getMe and asserts okMock { ok: true, result: { username: 'mybot' } }
verify() throws when ok === falseMock { ok: false, description: 'Unauthorized' }

Integration tests

TestApproach
Send to real Telegram group in CIUse a test bot and test group; assert message_id returned
verify() with real bot tokenAssert ok === true and bot username
Platform default used when no tenant rowSeed no notification_providers row; assert env vars used

Dev testing

Create a personal test bot via BotFather and a private Telegram group. Add TELEGRAM_BOT_TOKEN and TELEGRAM_DEFAULT_CHAT_ID to .env.dev. Messages will go to the dev group only.


© 2026 Leadmetrics — Internal use only