Telegram Bot API
Category: Notification — Messaging
Package: @leadmetrics/provider-telegram → TelegramBotProvider
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
- Message
@BotFatheron Telegram - Send
/newbotand follow prompts - Copy the bot token (format:
1234567890:ABCDEFxxxxxxxx) - Add the bot to the ops group/channel and make it an admin with “Post Messages” permission
- 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)
| Test | Approach |
|---|---|
send() POSTs to sendMessage endpoint | Mock axios.post; assert URL contains /sendMessage |
send() sends correct chat_id and text | Assert request body |
send() uses HTML parse mode by default | Assert parse_mode === 'HTML' |
send() returns messageId as string | Mock { ok: true, result: { message_id: 42 } } |
send() throws when ok === false | Mock { ok: false, description: 'Forbidden' } |
send() throws on network error | Mock axios.post rejects |
verify() calls getMe and asserts ok | Mock { ok: true, result: { username: 'mybot' } } |
verify() throws when ok === false | Mock { ok: false, description: 'Unauthorized' } |
Integration tests
| Test | Approach |
|---|---|
| Send to real Telegram group in CI | Use a test bot and test group; assert message_id returned |
verify() with real bot token | Assert ok === true and bot username |
| Platform default used when no tenant row | Seed 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.
Related
- WhatsApp Business API — client-facing messaging channel
- Notification Packages —
@leadmetrics/provider-telegramstructure - Notification Channels — Telegram handler detail
- Notification Providers — resolution pattern