telegix
v1.1.4
Published
Lightweight Telegram Bot API framework for Node.js.
Maintainers
Readme
⚡ Telegix
lightweight Telegram Bot API framework for Node.js, Bun, Deno, and modern JavaScript runtimes.
Telegix is a high-performance, developer-friendly Telegram Bot API library built with 100% Pure JavaScript and zero runtime dependencies beyond native platform APIs (fetch, FormData, Blob). It provides full, first-class support for the latest Telegram Bot API Specification, including Bot API 10.3.
📑 Table of Contents
- 🌟 Key Highlights
- 📦 Installation
- 🚀 Quick Start Guide
- 🏛️ Bot Core & Lifecycle
- 🛠️ Context (
ctx) Reference & Functions- Context Properties & Getters
- Text & HTML / Markdown Replies
- Media Sending Functions (Photos, Audio, Videos, Documents, Albums)
- Interactive Messages (Polls, Locations, Venues, Contacts, Dice, Stickers, Games)
- Message Reactions & Chat Actions
- Message Editing, Deleting, Forwarding, Copying, & Pinning
- Chat Administration & Member Moderation
- Forum Supergroups & Topics Management
- Bot API 10.2 & 10.3 Methods (Live Photos, Rich Messages, Drafts, Ephemeral Messages, Managed Access)
- 🎨 Rich Message & Layout Builder Suite (
RichMessage) - 📊 Table & Grid Formatting Suite (
Table&InputRichBlockTable)- 📱 Telegram Bot Card Tables (Rounded Card with Grid Dividers)
- 🤖 Pre-Configured & Fully Customizable System & User Profile Cards
- 💎 Multi-Card Stacking (
Table.multiCardSvg&ctx.replyWithCardTables) - Monospaced Text Tables (Box, ASCII, Compact, Markdown)
- Direct Context Table Replies (
ctx.replyWithTable) - Generating Tables from Objects (
Table.fromObjects) - Bot API 10.3 Native Rich Table Blocks
- 📸 Live Photos Suite (Bot API 10.2+)
- ↩️ Extended Reply Parameters & Ephemeral Commands (Bot API 10.2+)
- 🔵 Blue Text & Telegram Protocol Links (
tg://,documentLink,userLink) - ⏱️ Ephemeral Messages & Auto-Disappearing Lifetimes (
EphemeralMessageParameters) - 🚦 Composer & Router Engine
- 🎛️ Fluent Keyboard & Markup Builder (
Markup) - 🌊 Streaming Text for Bots (
streamText&streamDraft) - 💬 Asynchronous Conversations & Wizard Scenes
- 💾 Session & State Persistence
- 🌍 Internationalization & Localization (
I18n) - ✒️ Message Formatting (
fmt,html,mdv2) - 📜 Collapsible Quotes (
fmt,mdv2,RichMessage) - 🔗 Adjustable Link Previews (
LinkPreview) - 💳 Payments, Invoices & Telegram Stars (
InvoiceBuilder) - 📱 Telegram Mini Apps Suite (
MiniApp& Utilities) - 🤖 Multi-Bot Process Manager (
TelegixManager) - ⚡ Advanced Built-in Middlewares
- 📚 Complete Telegram API Client Method Reference (
bot.telegram/bot.api) - 💡 Example Scripts & Demos
- 🟦 TypeScript Support
- 🧪 Running Tests
- 📄 License
🌟 Key Highlights
- Pure JavaScript & Zero Runtime Dependencies: Built entirely on native Web standards (
fetch,FormData,Blob) with zero binary compilation and zero third-party packages. - Dual Module Architecture: Full, native compatibility with modern ESM (
import) and CommonJS (require). - Complete Telegram Bot API 10.2 & 10.3 Compliance: Built-in support for Live Photos (
sendLivePhoto,replyWithLivePhoto), message drafts (sendMessageDraft,sendRichMessageDraft), ephemeral messages (sendEphemeralMessage), extended reply parameters (checklist_task_id,poll_option_id,is_ephemeral), ephemeral commands (BotCommand.is_ephemeral), managed bot access settings (getManagedBotAccessSettings), disabled buttons (Markup.button.disabled), and Telegram Stars (XTR). - Rich Message Builder Suite: Fluent
RichMessageAPI with structured blocks, headers, badges, quotes, code blocks, interactive checklists (.checklist()), AI reasoning indicators (.thinking()), media layouts (.collage(),.slideshow()), and automatic HTML fallback compilation. - Table & Card Formatting Engine: Generate monospaced tables (
box,ascii,compact,markdown), native Bot API 10.3InputRichBlockTableblocks, and sleek Telegram Bot dark status cards with arbitrary dynamic fields (ctx.replyWithSystemStatus,ctx.replyWithUserProfile). - Blue Text & Telegram Protocol Links: Native helpers for
tg://document?id=...andtg://user?id=...to display blue clickable links in chat without external web routing. - Seamless Keyboard Normalization: Pass
Markup.keyboard()orMarkup.inlineKeyboard()directly as the 2nd argument toctx.reply()without manual JSON wrapping or extra payloads. - Asynchronous Inline Prompts: Await user answers step-by-step with
const answer = await ctx.prompt('What is your name?'). - Multi-Step Wizard Scenes: Structured conversation flows with
WizardSceneandStagefor complex interactive state machines. - Pluggable Session Storage: Includes
MemorySessionStore,FileSessionStore, and custom adapter support for Redis, MongoDB, or SQL databases. - XSS-Safe Dynamic Formatting: Tagged template literals with
fmtandhtmlprevent Telegram HTML parsing exceptions and script injection. - Multi-Bot Manager: Run and orchestrate hundreds of bot tokens simultaneously inside a single Node.js process using
TelegixManager.
📦 Installation
Install Telegix using your preferred package manager:
# Using npm
npm install telegix
# Using pnpm
pnpm add telegix
# Using yarn
yarn add telegix
# Using bun
bun add telegix🚀 Quick Start Guide
ECMAScript Modules (ESM)
Create a file named bot.mjs (or set "type": "module" in your package.json):
import { Telegix, Markup, RichMessage, fmt, html } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN');
// 1. Slash Command: /start
bot.command('start', async (ctx) => {
const name = ctx.from?.first_name || 'there';
await ctx.reply(
fmt`Hello, <b>${name}</b>! Welcome to <b>Telegix</b> ⚡`,
{ parse_mode: 'HTML' }
);
});
// 2. Custom Reply Keyboard: /menu
bot.command('menu', async (ctx) => {
const replyKeyboard = Markup.keyboard([
['☕ Coffee', '🍕 Pizza'],
['📊 Status', '⚙️ Settings'],
]).resize();
await ctx.reply('Please choose an option from the keyboard below:', replyKeyboard);
});
// 3. Inline Keyboard & Disabled Button (Bot API 10.3)
bot.command('order', async (ctx) => {
const inlineMenu = Markup.inlineKeyboard([
[
Markup.button.callback('Margherita ($10)', 'pizza_margherita'),
Markup.button.callback('Pepperoni ($12)', 'pizza_pepperoni'),
],
[
Markup.button.url('🌐 View Full Menu', 'https://example.com/menu'),
Markup.button.disabled('🔒 Truffle (Sold Out)'),
],
]);
await ctx.reply('Select your pizza:', inlineMenu);
});
// 4. Handle Inline Button Callbacks
bot.action(/^pizza_(.+)$/, async (ctx) => {
const selectedPizza = ctx.match[1];
await ctx.answerCallbackQuery(`Added ${selectedPizza} to your cart!`);
await ctx.editMessageText(
`✅ You selected: <b>${selectedPizza.toUpperCase()}</b>\nThank you for ordering!`,
{ parse_mode: 'HTML' }
);
});
// 5. Catch-All Text Messages with Reactions
bot.on('message:text', async (ctx) => {
await ctx.react('👍');
await ctx.reply(`You said: "${ctx.text}"`);
});
// Launch the bot with Long-Polling
bot.launch().then(() => {
console.log('🤖 Bot is online and listening for updates!');
});CommonJS (CJS)
Create a file named bot.js:
const { Telegix, Markup } = require('telegix');
const bot = new Telegix(process.env.BOT_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN');
bot.command('start', (ctx) => ctx.reply('Hello from Telegix CommonJS!'));
bot.launch().then(() => {
console.log('🤖 Bot is online!');
});🏛️ Bot Core & Lifecycle
Initialization & Configuration Options
The Telegix constructor accepts the bot token as its first parameter and an optional configuration object:
import { Telegix } from 'telegix';
const bot = new Telegix('123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', {
apiRoot: 'https://api.telegram.org', // Custom Bot API server URL (e.g. self-hosted server)
testEnv: false, // Connect to Telegram test environment
timeout: 60000, // Network HTTP request timeout in ms (default: 60000)
autoRetry: true, // Automatically retry after 429 Too Many Requests (default: true)
handlerTimeout: 90000, // Timeout in ms for update middleware execution
polling: {
timeout: 30, // Long-polling timeout in seconds (default: 30)
limit: 100, // Maximum updates to retrieve per polling request (default: 100)
allowedUpdates: [ // List of update types to receive
'message',
'edited_message',
'channel_post',
'edited_channel_post',
'business_connection',
'business_message',
'edited_business_message',
'deleted_business_messages',
'message_reaction',
'message_reaction_count',
'inline_query',
'chosen_inline_result',
'callback_query',
'shipping_query',
'pre_checkout_query',
'poll',
'poll_answer',
'my_chat_member',
'chat_member',
'chat_join_request',
'chat_boost',
'removed_chat_boost',
],
},
});Fetching Bot Info with getMe()
getMe() retrieves basic information about the bot in the form of a Telegram User object. You can call it directly on bot.telegram or through the ctx context inside any update:
// 1. Direct fetch before or outside update handling:
const botInfo = await bot.telegram.getMe();
console.log(`Bot Account: @${botInfo.username} (ID: ${botInfo.id})`);
console.log(`Can join groups: ${botInfo.can_join_groups}`);
console.log(`Can read all group messages: ${botInfo.can_read_all_group_messages}`);
console.log(`Supports inline queries: ${botInfo.supports_inline_queries}`);
// 2. Fetch inside any middleware or command handler:
bot.command('whoami', async (ctx) => {
const me = await ctx.getMe();
await ctx.reply(
`🤖 <b>Bot Details:</b>\n` +
`• Name: ${me.first_name}\n` +
`• Username: @${me.username}\n` +
`• Bot ID: <code>${me.id}</code>`,
{ parse_mode: 'HTML' }
);
});Long-Polling Mode
Start, monitor, and stop the long-polling lifecycle:
// Launch long-polling
await bot.launch({
dropPendingUpdates: true, // Drop updates accumulated while bot was offline
allowedUpdates: ['message', 'callback_query'],
});
// Manual polling controls
await bot.startPolling({ timeout: 30 });
// Gracefully stop the bot on process termination
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));Webhook Mode (Node.js HTTP, Express, Fastify, Serverless)
Use createWebhookCallback() to create a request handler compatible with all standard Node.js server frameworks:
Native Node.js http / https
import http from 'node:http';
import { Telegix, createWebhookCallback } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
const secretToken = 'my_super_secret_webhook_token';
// Set the webhook with Telegram
await bot.telegram.setWebhook('https://my-domain.com/webhook', {
secret_token: secretToken,
});
const server = http.createServer(
createWebhookCallback(bot, {
path: '/webhook',
secretToken: secretToken,
})
);
server.listen(3000, () => {
console.log('Webhook server running on port 3000');
});Express.js
import express from 'express';
import { Telegix, createWebhookCallback } from 'telegix';
const app = express();
const bot = new Telegix(process.env.BOT_TOKEN);
app.use(express.json());
app.post('/webhook', createWebhookCallback(bot, { secretToken: process.env.WEBHOOK_SECRET }));
app.listen(3000);Multi-Core Cluster Mode
Scale your bot horizontally across all CPU cores on a multi-core server:
import { Telegix } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
// Spawn a worker for each CPU core automatically
if (bot.cluster()) {
// Primary process manages child worker lifecycles
} else {
// Worker process handles bot updates
bot.command('ping', (ctx) => ctx.reply(`Pong from worker ${process.pid}!`));
bot.launch();
}Error Handling & bot.catch()
Catch and handle uncaught errors gracefully across all middlewares:
import { TelegramError } from 'telegix';
bot.catch((err, ctx) => {
console.error(`Error occurred while handling update ${ctx.update.update_id}:`, err);
if (err instanceof TelegramError) {
console.error(`Telegram API Error [${err.errorCode}]: ${err.description}`);
if (err.parameters?.retry_after) {
console.warn(`Rate limit retry after: ${err.parameters.retry_after}s`);
}
}
// Attempt to notify user if possible
ctx.reply('⚠️ An unexpected error occurred while processing your request.').catch(() => {});
});🛠️ Context (ctx) Reference & Functions
Every middleware, command, and event handler receives a Context instance (ctx) encapsulating the current update and providing dozens of helper methods.
Context Properties & Getters
| Property / Getter | Type | Description |
|---|---|---|
| ctx.update | object | The raw Telegram Update object received from Telegram Bot API. |
| ctx.updateType | string | The primary update type (e.g., 'message', 'callback_query', 'chat_boost'). |
| ctx.updateSubtypes | string[] | Subtype classifications (e.g., ['text'], ['photo'], ['pinned_message']). |
| ctx.botInfo | object | The cached User object of this bot. |
| ctx.telegram / ctx.api | Telegram | The low-level Telegram API client instance. |
| ctx.state | object | Clean per-update state dictionary to share data between middlewares. |
| ctx.session | object | Persistent session object (when session() middleware is enabled). |
| ctx.message / ctx.msg | object\|null | Shortcut to incoming Message (or edited message, channel post, business message). |
| ctx.chat | object\|null | The Chat object associated with the current update. |
| ctx.chatId | number\|string | ID of the current chat. |
| ctx.from | object\|null | The User object of the sender. |
| ctx.userId | number | ID of the sender user. |
| ctx.text | string\|null | Text content of the current message. |
| ctx.callbackQuery | object\|null | CallbackQuery object if this update is a button callback. |
| ctx.inlineQuery | object\|null | InlineQuery object if this update is an inline query. |
| ctx.match | RegExpMatchArray | Regex match results when triggered via bot.hears() or bot.action(). |
| ctx.payload | string | Command arguments payload after a slash command (e.g. /ban 123 -> '123'). |
| ctx.isForum | boolean | true if the current chat is a forum supergroup. |
| ctx.topicId | number\|null | Forum thread ID / Message Thread ID if inside a forum topic. |
Text & HTML / Markdown Replies
// Plain text reply
await ctx.reply('Hello, World!');
// HTML formatted reply
await ctx.replyWithHTML('<b>Bold</b>, <i>Italic</i>, <code>Code</code>, <a href="https://telegix.dev">Link</a>');
// Markdown formatted reply
await ctx.replyWithMarkdown('*Bold text*, _Italic text_, `Code`');
// MarkdownV2 formatted reply
await ctx.replyWithMarkdownV2('*Bold* and _Italic_ and ||Spoiler||');
// Reply with additional options and keyboard
await ctx.reply('Choose an option:', {
parse_mode: 'HTML',
reply_to_message_id: ctx.message?.message_id,
reply_markup: Markup.inlineKeyboard([
[Markup.button.callback('Option 1', 'opt_1')],
]),
});
// Stream real-time tokens/text with automated throttle control
await ctx.streamText(tokenGenerator(), { initialMessage: '⏳ Thinking...' });
// Stream real-time draft into chat input bar (Bot API 10.3)
await ctx.streamDraft(tokenGenerator());
// Reply with customized link preview (small/large, above/below, disabled)
await ctx.replyWithLinkPreview('Visit Docs:', LinkPreview.large('https://telegix.dev'));
// Reply with expandable/collapsible blockquote
await ctx.replyWithCollapsibleQuote('Full debug stack trace...', '⚠️ <b>System Warning</b>');
// Reply with button launching a Telegram Mini App
await ctx.replyWithWebApp('Launch Dashboard:', 'https://app.example.com', '🚀 Open App');
// Reply with formatted monospaced table (Box, Compact, ASCII, Markdown)
await ctx.replyWithTable(['Item', 'Price'], [['Pro Plan', '$29'], ['Addon', '$5']], { style: 'box' });
// Reply with auto-disappearing ephemeral message (Bot API 10.3)
await ctx.replyEphemeral('This message will disappear in 15 seconds.', 15);
// Save a prepared inline message for Mini App sharing (Bot API 8.0+)
const prepared = await ctx.savePreparedInlineMessage({
type: 'article',
id: 'share_1',
title: 'Share Score',
input_message_content: { message_text: 'I reached Level 10!' },
});
// Retrieve bot user identity
const me = await ctx.getMe();Media Sending Functions (Photos, Audio, Videos, Documents, Albums)
// 1. Send Photo (by URL, File ID, Blob, or Buffer)
await ctx.replyWithPhoto('https://example.com/image.jpg', {
caption: '🌅 Beautiful sunset in HTML: <b>Nature</b>',
parse_mode: 'HTML',
});
// 2. Send Audio File
await ctx.replyWithAudio('https://example.com/song.mp3', {
title: 'Track Title',
performer: 'Artist Name',
caption: '🎵 Enjoy the music!',
});
// 3. Send Document / File
await ctx.replyWithDocument('https://example.com/manual.pdf', {
caption: '📄 User Manual PDF',
});
// 4. Send Video
await ctx.replyWithVideo('https://example.com/clip.mp4', {
caption: '🎬 Video Showcase',
supports_streaming: true,
});
// 5. Send Animation / GIF
await ctx.replyWithAnimation('https://example.com/cheers.gif');
// 6. Send Voice Note (.ogg audio)
await ctx.replyWithVoice('https://example.com/voice.ogg');
// 7. Send Video Note (Round video message)
await ctx.replyWithVideoNote('https://example.com/round_video.mp4');
// 8. Send Media Group / Photo Album
await ctx.replyWithMediaGroup([
{ type: 'photo', media: 'https://example.com/photo1.jpg', caption: 'Photo 1' },
{ type: 'photo', media: 'https://example.com/photo2.jpg' },
{ type: 'video', media: 'https://example.com/video1.mp4' },
]);
// 9. Send Live Photo (Bot API 10.2+)
await ctx.replyWithLivePhoto(
'https://example.com/cover.jpg',
'https://example.com/motion.mp4',
{ caption: '📸 Dynamic Live Photo' }
);Interactive Messages (Polls, Locations, Venues, Contacts, Dice, Stickers, Games)
// 1. Send Location (Latitude, Longitude)
await ctx.replyWithLocation(37.7749, -122.4194);
// 2. Send Venue
await ctx.replyWithVenue(37.7749, -122.4194, 'San Francisco City Hall', '1 Dr Carlton B Goodlett Pl');
// 3. Send Contact Card
await ctx.replyWithContact('+1234567890', 'John', { last_name: 'Doe' });
// 4. Send Poll or Quiz
await ctx.replyWithPoll(
'Which database do you prefer?',
['PostgreSQL', 'Redis', 'MongoDB', 'SQLite'],
{
is_anonymous: false,
allows_multiple_answers: true,
}
);
// 5. Send Animated Dice (🎲, 🎯, 🏀, ⚽, 🎰, 🎳)
await ctx.replyWithDice({ emoji: '🎯' });
// 6. Send Sticker
await ctx.replyWithSticker('CAACAgIAAxkBAAE...');
// 7. Send Telegram Game
await ctx.replyWithGame('my_telegix_game');
// 8. Send Paid Media (Telegram Stars)
await ctx.replyWithPaidMedia(25, [
{ type: 'photo', media: 'https://example.com/exclusive_art.jpg' }
]);Message Reactions & Chat Actions
// Add an emoji reaction to the current message
await ctx.react('❤️');
await ctx.react('🔥');
// Send chat action indicators ('typing', 'upload_photo', 'record_video', 'upload_document', etc.)
await ctx.replyWithChatAction('typing');
await ctx.replyWithChatAction('upload_document');Message Editing, Deleting, Forwarding, Copying, & Pinning
// 1. Edit current message text
await ctx.editMessageText('Updated text content', { parse_mode: 'HTML' });
// 2. Edit current message caption
await ctx.editMessageCaption('Updated media caption');
// 3. Edit current message reply markup
await ctx.editMessageReplyMarkup(
Markup.inlineKeyboard([[Markup.button.callback('New Option', 'opt_new')]])
);
// 4. Delete messages
await ctx.deleteMessage(); // Deletes current incoming message
await ctx.deleteMessage(targetMessageId);
await ctx.deleteMessages([msgId1, msgId2, msgId3]);
// 5. Forward or Copy messages to another chat
await ctx.forwardMessage(targetChatId);
await ctx.copyMessage(targetChatId);
// 6. Pin / Unpin messages
await ctx.pinChatMessage();
await ctx.unpinChatMessage();
await ctx.unpinAllChatMessages();
// 7. Answer Callback Query
await ctx.answerCallbackQuery('Action confirmed!', { show_alert: false });Chat Administration & Member Moderation
// Get Chat Details & Administrators
const chat = await ctx.getChat();
const admins = await ctx.getChatAdministrators();
// Get Member Info & Total Member Count
const member = await ctx.getChatMember(targetUserId);
const count = await ctx.getChatMembersCount();
// Ban / Kick Member
await ctx.banChatMember(targetUserId, {
until_date: Math.floor(Date.now() / 1000) + 86400, // 24 hours ban
revoke_messages: true,
});
// Unban Member
await ctx.unbanChatMember(targetUserId, { only_if_banned: true });
// Restrict Permissions
await ctx.restrictChatMember(targetUserId, {
can_send_messages: false,
can_send_media_messages: false,
can_send_other_messages: false,
can_add_web_page_previews: false,
});
// Promote Member to Administrator
await ctx.promoteChatMember(targetUserId, {
can_change_info: true,
can_delete_messages: true,
can_invite_users: true,
can_pin_messages: true,
});
// Manage Chat Info
await ctx.setChatTitle('New Group Title');
await ctx.setChatDescription('Updated group description.');
await ctx.leaveChat();Forum Supergroups & Topics Management
// Check if the current chat is a forum supergroup
if (ctx.isForum) {
console.log('Current forum thread ID:', ctx.topicId);
}
// Create a new topic in a forum supergroup
const topic = await ctx.createForumTopic('🚀 Development Updates', {
icon_color: 0x6FB9F0,
icon_custom_emoji_id: '5312345678901234567',
});
// Edit, Close, Reopen, or Delete Topics
await ctx.editForumTopic(ctx.topicId, { name: '📁 Archived Updates' });
await ctx.closeForumTopic(ctx.topicId);
await ctx.reopenForumTopic(ctx.topicId);
await ctx.deleteForumTopic(ctx.topicId);
await ctx.unpinAllForumTopicMessages(ctx.topicId);Bot API 10.2 & 10.3 Methods (Live Photos, Rich Messages, Drafts, Ephemeral Messages, Managed Access)
import { RichMessage, Markup, ReplyParameters } from 'telegix';
// 1. Send Live Photo (Bot API 10.2+)
await ctx.replyWithLivePhoto(
'https://example.com/photo.jpg',
'https://example.com/video.mp4',
{ caption: '✨ Interactive Live Photo' }
);
// 2. Send Rich Message (structured layout blocks with automatic fallback)
const card = RichMessage.card('⚡ Server Health Check', 'All systems operational.')
.header('Cluster Status', '🟢')
.badge('CPU Load', '14%')
.badge('Memory', '1.2 GB / 8.0 GB')
.checklist([
{ text: 'Database connectivity', is_checked: true },
{ text: 'Redis cache synchronization', is_checked: true },
{ text: 'Worker nodes online', is_checked: false },
])
.expandableQuote('Rich messages provide structured block layouts.')
.row(
Markup.button.callback('🔄 Refresh', 'refresh_stats'),
Markup.button.disabled('🔒 Advanced Tuning')
);
await ctx.replyWithRichMessage(card);
// 3. Edit existing message with Rich Message
await ctx.editRichMessageText(card);
// 4. Send Rich Message Draft
await ctx.sendRichMessageDraft(card);
// 5. Send Message Draft (Real-time draft displayed directly in user client)
await ctx.sendMessageDraft('Bot is currently preparing your report...');
// 6. Send Ephemeral Message (Message with automated lifetime)
await ctx.sendEphemeralMessage('This message will automatically vanish in 15 seconds.', 15);
// 7. Extended ReplyParameters (Bot API 10.2+)
await ctx.reply('Replying to specific checklist task:', {
reply_parameters: {
message_id: ctx.message?.message_id,
checklist_task_id: 2,
allow_sending_without_reply: true,
},
});
// 8. Managed Bot Access Settings (Bot API 10.3)
const accessSettings = await ctx.getManagedBotAccessSettings(adminUserId);
await ctx.setManagedBotAccessSettings({ allow_admin_override: true }, adminUserId);
// 9. Get User Personal Chat Messages
const messages = await ctx.getUserPersonalChatMessages(targetUserId);🎨 Rich Message & Layout Builder Suite (RichMessage)
The RichMessage class allows you to construct modern, structured card layouts, dashboards, and rich messages using a fluent chaining syntax.
Fluent Block Builder API
| Builder Method | Description |
|---|---|
| .header(text, emoji?) | Adds a prominent header block with an optional leading emoji. |
| .paragraph(text) | Adds a body paragraph block. |
| .bold(text) / .italic(text) | Adds bold or italic styled text blocks. |
| .underline(text) / .strikethrough(text) | Adds underlined or struck-through text blocks. |
| .code(codeText, language?) | Adds inline or syntax-highlighted multiline code blocks. |
| .quote(text, expandable?) | Adds a standard or expandable Telegram blockquote. |
| .expandableQuote(text) | Shortcut to add an expandable blockquote. |
| .spoiler(text) | Adds tap-to-reveal spoiler formatted text. |
| .link(text, url) | Adds a formatted hyperlink. |
| .mention(text, userId) | Adds an inline mention link for a Telegram user ID. |
| .list(items, bullet?) | Formats an array of strings into a bulleted list. |
| .numberedList(items) | Formats an array of strings into a numbered list (1., 2., 3.). |
| .checklist(items, options?) | Adds an interactive task checklist block with checkbox states (is_checked: boolean) (Bot API 10.2+). |
| .thinking(text) | Adds an AI reasoning/thinking status indicator block. |
| .sectionHeading(text, level?) | Adds a section heading block with semantic level 1-3. |
| .collage(photos, options?) | Arranges multiple photos into a cohesive photo grid collage. |
| .slideshow(photos, options?) | Arranges media into a sequential interactive slideshow. |
| .isRtl(boolean) | Sets Right-to-Left script direction (Arabic, Hebrew, Persian). |
| .addMedia(media, options?) / .media(...) | Attaches a media object (photo, video, audio) to the rich message. |
| .table(headers, rows, options?) | Adds a structured table block (Bot API 10.3 Native Block or HTML pre-formatted fallback). |
| .compactTable(headers, rows, options?) | Adds a compact table block with minimal padding for mobile. |
| .document(document, caption?, options?) | Adds a rich document block attachment. |
| .documentLink(documentId, text?) | Adds an inline blue document download link (tg://document?id=...). |
| .badge(label, value, icon?) | Adds a key-value metric badge item. |
| .divider() | Inserts a clean visual separator line. |
| .buttons(matrix) | Appends a matrix of inline keyboard buttons as a block. |
| .row(...buttons) | Appends a row of inline keyboard buttons. |
| .callback(text, data) | Appends an inline callback query button. |
| .url(text, url) | Appends an external URL link button. |
| .disabled(text) | Appends a non-clickable disabled button (Bot API 10.3). |
| .ephemeral(seconds) | Sets message lifetime parameter for auto-expiration. |
| .draftId(id?) / .asDraft() | Configures the rich message as a real-time message draft. |
| .compile() / .build() | Compiles all blocks into a Telegram-ready payload object. |
| .send(ctx) | Sends the rich message using the active context. |
| .edit(ctx) | Edits an existing message with this rich message. |
Interactive Checklist Blocks (Bot API 10.2+)
Telegram Bot API 10.2 introduced interactive checklist blocks (InputRichBlockChecklist). Telegix provides first-class support for defining tasks with dynamic completion states:
import { RichMessage, Markup } from 'telegix';
bot.command('tasks', async (ctx) => {
const msg = RichMessage.create('📋 <b>Sprint Tasks</b>')
.sectionHeading('Milestone 1 Deliverables', 2)
.checklist([
{ text: 'Complete Bot API 10.2 Live Photo integration', is_checked: true },
{ text: 'Implement Checklist rich blocks', is_checked: true },
{ text: 'Ship documentation and example suite', is_checked: false },
])
.divider()
.row(
Markup.button.success('Mark All Done', 'tasks_complete_all'),
Markup.button.primary('Refresh', 'tasks_refresh')
);
await ctx.replyWithRichMessage(msg);
});AI Thinking Indicator & Media Layouts (Collage, Slideshow)
Modern AI assistants can indicate active reasoning and thinking stages before displaying output:
bot.command('ai_diagnose', async (ctx) => {
const report = RichMessage.create('🤖 <b>System Diagnosis</b>')
.thinking('Analyzing latency metrics across distributed clusters...')
.sectionHeading('Cluster Health Evaluation', 2)
.badge('Status', 'Nominal', '🟢')
.badge('Load Average', '0.42', '⚡')
.collage([
'https://example.com/chart1.png',
'https://example.com/chart2.png',
])
.slideshow([
'https://example.com/slide1.png',
'https://example.com/slide2.png',
]);
await ctx.replyWithRichMessage(report);
});Static Factory Methods
import { RichMessage } from 'telegix';
// Create a blank builder
const msg = RichMessage.create('Optional initial text');
// Create a pre-structured Card
const card = RichMessage.card('Card Title', 'Card Description', [
Markup.button.callback('Click Me', 'btn_1'),
]);
// Create a Draft Message
const draft = RichMessage.draft('Drafting text...', 12345);
// Create an Ephemeral Message
const expiring = RichMessage.ephemeral('Expiring note', 30);
// Create a Table Rich Message
const tableCard = RichMessage.table(['ID', 'Item', 'Price'], [
['#1', 'Server Pro', '$49/mo'],
['#2', 'Database Addon', '$19/mo'],
]);
// Create a Compact Table Rich Message (Optimized for Mobile)
const compactCard = RichMessage.compactTable(['Crypto', 'Change'], [
['BTC', '+5.4%'],
['ETH', '+2.1%'],
]);Complete Interactive Rich Card Example
import { Telegix, Markup, RichMessage } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
bot.command('dashboard', async (ctx) => {
const dashboard = RichMessage.card('⚡ Infrastructure Dashboard', 'Live metrics from production cluster:')
.header('Cluster Status', '🟢')
.badge('CPU Utilization', '28.4%', '💻')
.badge('RAM Usage', '3.8 GB / 16.0 GB', '🧠')
.badge('Active Connections', '1,420', '🌐')
.badge('Error Rate', '0.002%', '🛡️')
.divider()
.header('Active Worker Nodes', '🖥️')
.list([
'worker-ap-southeast-1a: Healthy (0.12 load)',
'worker-ap-southeast-1b: Healthy (0.15 load)',
'worker-ap-southeast-1c: Standby',
])
.divider()
.expandableQuote('Auto-scaling policy is currently enabled. Additional instances will spawn if CPU exceeds 75%.')
.code('curl -s https://api.cluster.internal/v1/health | jq', 'bash')
.row(
Markup.button.callback('🔄 Refresh Data', 'refresh_metrics'),
Markup.button.url('📈 Grafana', 'https://grafana.example.com')
)
.row(
Markup.button.disabled('🔒 Deploy Patch (Admin Only)')
);
await ctx.replyWithRichMessage(dashboard);
});📊 Table & Grid Formatting Suite (Table & InputRichBlockTable)
Telegram does not have a native HTML <table> tag, meaning standard HTML tables fail to render. Telegix solves this by providing a comprehensive, zero-dependency Table formatting suite and native Bot API 10.3 InputRichBlockTable support.
Whether you need modern Telegram Bot card tables with rounded borders and column dividers, Unicode box borders, minimal compact lines for mobile screens, or markdown tables, Telegix formats and renders them seamlessly.
📱 Telegram Bot Card Tables (Rounded Card with Grid Dividers)
Modern Telegram bots frequently display dashboard and status metrics as sleek card tables featuring:
- 🔲 Rounded Card Container (
rx="12",#18222dbackground,#2b3d4fborder) - 📐 Vertical Column Divider Line cleanly separating labels (left) and values (right)
- ➖ Horizontal Row Divider Lines between every item
- 🏷️ Header Banner with distinct background (
#1c2836) and bold title - 🔵 Telegram Blue Links for handles (e.g.
@username) and protocol URLs
import { Telegix, Table } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
// Create a custom card table
const cardTable = Table.card(
['📦 SYSTEM', 'Status'],
[
['Engine', 'Telegix'],
['Runtime', '0h 19m 32s'],
['Node', 'v23.11'],
['Features', 514],
['Groups', 168],
['Users', 9528],
]
);
// Method 1: Send directly with ctx helper
bot.command('status', async (ctx) => {
await ctx.replyWithTableCard(cardTable);
});
// Method 2: Send as vector card image
bot.command('card_img', async (ctx) => {
await ctx.replyWithTableCard(cardTable, [], { asImage: true });
});🤖 Pre-Configured & Fully Customizable System & User Profile Cards
Telegix provides built-in card factories and context helpers for status monitoring and user profile displays with full customization support:
1. Arbitrary Dynamic Fields
Pass any custom key-value pairs; Telegix automatically formats human-readable labels from keys (e.g. ram_usage -> Ram Usage, db_cluster -> Db Cluster):
// System Status with custom metrics
await ctx.replyWithSystemStatus({
engine: 'Telegix',
runtime: '3d 14h 28m',
node: process.version,
features: 514,
groups: 168,
users: 9528,
ram_usage: '142 MB / 1024 MB',
database: 'PostgreSQL 17',
active_cluster: 'Singapore-Node-1',
ping: '14ms',
});
// User Profile with custom fields
await ctx.replyWithUserProfile({
username: '@alice_dev',
status: 'VIP Elite Member',
balance: '$250.00 USD',
reward_points: 14500,
api_quota: 'Unlimited',
registered: 'September 2026',
});2. Custom Header Title & Subtitle
Customize the card header banner text:
await ctx.replyWithSystemStatus({
title: '🖥️ CLUSTER MONITOR',
subtitle: 'Region Asia-Southeast1',
engine: 'Telegix Engine',
runtime: '12h 45m',
memory_load: '32%',
});
await ctx.replyWithUserProfile({
title: '👑 VIP MEMBERSHIP',
subtitle: 'Tier 3 Account',
username: '@username',
status: 'Verified Developer',
});3. Raw Structured 2D Array Matrix
Supply exact rows without key formatting:
await ctx.replyWithSystemStatus({
title: '📊 TELEMETRY',
rows: [
['Cluster Pod', 'k8s-sg-node-01'],
['CPU Throttling', '0.00%'],
['Memory Pressure', 'Normal'],
],
});💎 Multi-Card Stacking (Table.multiCardSvg & ctx.replyWithCardTables)
Stack multiple cards (such as SYSTEM and PROFILE) in a single message or render them unified:
bot.command('dashboard', async (ctx) => {
const sysCard = Table.systemStatus();
const profileCard = Table.userProfile({
username: ctx.from?.username ? `@${ctx.from.username}` : '@username',
});
// Sends both cards stacked together cleanly in chat
await ctx.replyWithCardTables([sysCard, profileCard]);
// Or send as a single unified high-definition graphic:
// await ctx.replyWithCardTables([sysCard, profileCard], { asImage: true });
});Monospaced Text Tables (Box, ASCII, Compact, Markdown)
import { Table } from 'telegix';
const headers = ['Symbol', 'Asset', 'Price', '24h'];
const rows = [
['BTC', 'Bitcoin', '$64,250', '+3.2%'],
['ETH', 'Ethereum', '$3,480', '+1.8%'],
['SOL', 'Solana', '$142.50', '+5.9%'],
['TON', 'Toncoin', '$5.60', '+8.1%'],
];
// 1. Box Style (Unicode border: ┌───┬───┐)
const boxTable = Table.box(headers, rows, {
title: '📈 Market Leaders',
alignments: ['left', 'left', 'right', 'right'],
});
// 2. Compact Style (Minimal divider, optimized for small mobile phone screens)
const compactTable = Table.compact(headers, rows);
// 3. ASCII Style (Classic terminal style: +---+---+)
const asciiTable = Table.ascii(headers, rows);
// 4. Markdown Style (GitHub flavored markdown table)
const mdTable = Table.markdown(headers, rows);
// 5. HTML Pre-Formatted Helper (Wraps table in <pre> tags for ctx.reply)
const htmlTable = new Table(headers, rows).toHtml({
style: 'box',
title: 'Cryptocurrency Rates',
});Direct Context Table Replies (ctx.replyWithTable)
Send beautiful formatted tables with a single function call:
bot.command('rates', async (ctx) => {
const headers = ['Plan', 'Storage', 'Price'];
const rows = [
['Starter', '10 GB', '$5/mo'],
['Pro', '100 GB', '$15/mo'],
['Enterprise', '1 TB', '$49/mo'],
];
// Dispatches an HTML pre-formatted table wrapped in <pre>
await ctx.replyWithTable(headers, rows, {
style: 'box', // 'box' | 'compact' | 'ascii' | 'markdown'
title: '💾 Cloud Storage Plans',
alignments: ['left', 'center', 'right'],
});
});Generating Tables from Objects (Table.fromObjects)
Turn arbitrary JavaScript arrays of objects directly into tables without manual data mapping:
const users = [
{ id: 101, name: 'Alice', role: 'Admin', score: 98 },
{ id: 102, name: 'Bob', role: 'Editor', score: 85 },
{ id: 103, name: 'Charlie', role: 'Viewer', score: 72 },
];
// Automatically extracts column names and values:
const table = Table.fromObjects(users, ['id', 'name', 'role', 'score'], {
style: 'compact',
title: '👥 Team Directory',
});
await ctx.reply(table.toHtml(), { parse_mode: 'HTML' });Bot API 10.3 Native Rich Table Blocks
For clients supporting Bot API 10.3 structured blocks, use RichMessage.table() or InputRichBlockTable directly:
import { RichMessage, Markup } from 'telegix';
bot.command('leaderboard', async (ctx) => {
const card = RichMessage.card('🏆 Tournament Standings', 'Season 4 Grand Finalists')
.header('Top Scorers', '🥇')
.table(
['Rank', 'Player', 'Score'],
[
['1st', 'Alex', '4,850'],
['2nd', 'Beatrix', '4,720'],
['3rd', 'Carlos', '4,210'],
],
{ is_compact: true } // Bot API 10.3 is_compact flag
)
.divider()
.row(
Markup.button.primary('🔄 Refresh Standings', 'refresh_leaderboard'),
Markup.button.url('🌐 Full Web Table', 'https://example.com/tournament')
);
await ctx.replyWithRichMessage(card);
});📸 Live Photos Suite (Bot API 10.2+)
Telegram Bot API 10.2 introduced support for sending Live Photos—interactive photos paired with micro-videos that animate when tapped and held in Telegram clients.
Telegix provides both context helper methods (ctx.replyWithLivePhoto) and low-level API client methods (bot.telegram.sendLivePhoto):
import { Telegix } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
// 1. Context Reply Shortcut: ctx.replyWithLivePhoto(photo, video, extra?)
bot.command('livephoto', async (ctx) => {
await ctx.replyWithLivePhoto(
'https://example.com/photo.jpg',
'https://example.com/live_motion.mp4',
{
caption: '📸 <b>Interactive Live Photo</b>\n<i>Tap and hold to play animation!</i>',
parse_mode: 'HTML',
}
);
});
// 2. Telegram API Client: bot.telegram.sendLivePhoto(chatId, photo, video, extra?)
await bot.telegram.sendLivePhoto(
chatId,
'https://example.com/photo.jpg',
'https://example.com/live_motion.mp4',
{ caption: 'Captured Live Moment' }
);↩️ Extended Reply Parameters & Ephemeral Commands (Bot API 10.2+)
Telegram Bot API 10.2 expanded ReplyParameters and bot command configurations with specialized fields for fine-grained reply targets and message visibility.
1. Extended ReplyParameters (checklist_task_id, poll_option_id, is_ephemeral)
You can now target specific checklist tasks, poll options, or designate replies as ephemeral:
import { ReplyParameters } from 'telegix';
// Target a specific task item inside an interactive checklist
bot.command('check_done', async (ctx) => {
await ctx.reply('✅ Task #2 marked completed!', {
reply_parameters: {
message_id: ctx.message?.message_id,
checklist_task_id: 2, // Bot API 10.2+
allow_sending_without_reply: true,
},
});
});
// Target a specific option within a poll
bot.command('poll_comment', async (ctx) => {
await ctx.reply('Insightful vote on option #1!', {
reply_parameters: new ReplyParameters({
message_id: targetPollMessageId,
poll_option_id: 'opt_1', // Bot API 10.2+
}),
});
});2. Ephemeral Bot Commands (BotCommand.is_ephemeral)
Mark specific bot commands as ephemeral so their responses are only visible to the user who invoked them, keeping group conversations clean:
import { BotCommand } from 'telegix';
const commands = [
new BotCommand('start', 'Open main menu'),
new BotCommand('help', 'Show help information'),
new BotCommand('mybalance', 'Check personal balance privately', {
is_ephemeral: true, // Bot API 10.2+
}),
];
await bot.telegram.setMyCommands(commands);🔵 Blue Text & Telegram Protocol Links (tg://, documentLink, userLink)
In Telegram chats, clickable links and protocol handlers are rendered in Telegram's signature blue text color. Telegix provides first-class helpers to generate these links cleanly across HTML, Markdown, and template literals:
Blue Document Links (tg://document?id=...)
Generate blue clickable download links pointing directly to Telegram document file IDs or catalog items without external web servers:
import { fmt, html, markdown } from 'telegix';
// 1. Using HTML helper: html.documentLink(documentId, text)
const docLinkHtml = html.documentLink('10987654321', '📄 Download Financial Q3 Report (Blue Text)');
// -> <a href="tg://document?id=10987654321">📄 Download Financial Q3 Report (Blue Text)</a>
// 2. Using Markdown helper: markdown.documentLink(documentId, text)
const docLinkMd = markdown.documentLink('10987654321', 'Download Specification');
// -> [Download Specification](tg://document?id=10987654321)
// 3. Using Tagged Template Literal: fmt.documentLink
bot.command('specs', async (ctx) => {
await ctx.reply(
fmt`
📋 <b>Project Specifications</b>
Click the blue document link below to open the file:
${fmt.documentLink('987654321', '📄 View Architecture Blueprint')}
`,
{ parse_mode: 'HTML' }
);
});Blue User Mention Links (tg://user?id=...)
Generate blue profile links that open a user's Telegram profile card when tapped:
import { html, fmt } from 'telegix';
bot.command('moderator', async (ctx) => {
const modId = 123456789;
const modName = 'Support Admin';
await ctx.reply(
fmt`Need assistance? Contact our on-duty moderator: ${html.userLink(modId, modName)}`,
{ parse_mode: 'HTML' }
);
});Blue Primary Buttons & Colored Buttons
Telegram Bot API 9.4+ introduced colored inline buttons. Use Markup.button.primary() to render prominent blue action buttons that match Telegram's blue link aesthetic:
import { Markup } from 'telegix';
const blueKeyboard = Markup.inlineKeyboard([
[
Markup.button.primary('🔵 Primary Action (Blue)', 'btn_primary_click'),
Markup.button.url('🌐 Blue Web Link', 'https://telegix.dev'),
],
[
Markup.button.colored('📄 Document Protocol', 'primary', 'tg://document?id=12345'),
],
]);
await ctx.reply('Select an action:', blueKeyboard);⏱️ Ephemeral Messages & Auto-Disappearing Lifetimes (EphemeralMessageParameters)
Telegram Bot API 10.3 introduced Ephemeral Messages — temporary messages configured with an automatic lifetime that vanish after the specified duration expires.
Telegix provides the EphemeralMessageParameters builder and native ctx.replyEphemeral() shortcut:
import { EphemeralMessageParameters } from 'telegix';
// 1. Direct Context shortcut with duration in seconds:
bot.command('secret', async (ctx) => {
// Automatically self-destructs in 15 seconds
await ctx.replyEphemeral('🤫 This secret passcode will disappear in 15 seconds: 884-219', 15);
});
// 2. Fluent EphemeralMessageParameters builder:
bot.action('show_token', async (ctx) => {
await ctx.answerCallbackQuery();
const params = EphemeralMessageParameters.create(30)
.receiver(ctx.from.id) // Target specific user ID
.callbackQuery(ctx.callbackQuery.id) // Bind to callback query
.replaceCallbackQueryMessage(true); // Replace origin message
await ctx.replyEphemeral(
'🔑 <b>Single-Use Access Token:</b> <code>tok_99182a8bf3</code>\n<i>Disappears in 30s.</i>',
params,
{ parse_mode: 'HTML' }
);
});
// 3. Edit or delete ephemeral messages:
await ctx.editEphemeralMessageText('Updated ephemeral text');
await ctx.deleteEphemeralMessage();🚦 Composer & Router Engine
Composer powers the routing and middleware pipeline in Telegix.
Event Filtering (bot.on)
Filter and intercept incoming updates by type and subtype:
// Text messages
bot.on('message:text', async (ctx) => { ... });
// Photos, Audios, Documents, Videos
bot.on('message:photo', async (ctx) => { ... });
bot.on('message:audio', async (ctx) => { ... });
bot.on('message:document', async (ctx) => { ... });
bot.on('message:video', async (ctx) => { ... });
// Service messages
bot.on('message:new_chat_members', async (ctx) => { ... });
bot.on('message:left_chat_member', async (ctx) => { ... });
bot.on('message:pinned_message', async (ctx) => { ... });
// Channel Posts
bot.on('channel_post:text', async (ctx) => { ... });
// Inline Queries & Results
bot.on('inline_query', async (ctx) => { ... });
bot.on('chosen_inline_result', async (ctx) => { ... });
// Reactions & Boosts
bot.on('message_reaction', async (ctx) => { ... });
bot.on('chat_boost', async (ctx) => { ... });
// Listen to multiple event types at once
bot.on(['message:voice', 'message:video_note'], async (ctx) => { ... });Slash Commands (bot.command)
Handles slash commands and parses command arguments into ctx.payload:
// Matches /start
bot.command('start', async (ctx) => {
await ctx.reply('Welcome!');
});
// Matches /ban <userId> <reason>
bot.command('ban', async (ctx) => {
const [targetId, ...reasonParts] = ctx.payload.split(' ');
const reason = reasonParts.join(' ');
await ctx.reply(`Banning user ${targetId} for reason: ${reason}`);
});
// Matches multiple commands simultaneously
bot.command(['help', 'info', 'guide'], async (ctx) => {
await ctx.reply('Help documentation...');
});Text Pattern Matching (bot.hears)
Match message text or captions against static strings or Regular Expressions:
// Static string matching
bot.hears('hi', async (ctx) => ctx.reply('Hello there!'));
// Regular expression matching with capture groups
bot.hears(/^echo (.+)$/i, async (ctx) => {
const capturedText = ctx.match[1];
await ctx.reply(`Echo: ${capturedText}`);
});
// Match multiple phrases
bot.hears(['help', 'support', 'contact'], async (ctx) => {
await ctx.reply('Please email [email protected] for assistance.');
});Button Callbacks (bot.action)
Handle inline button callback queries with exact strings or regex matching:
// Exact match
bot.action('confirm_delete', async (ctx) => {
await ctx.answerCallbackQuery('Item deleted!');
await ctx.deleteMessage();
});
// Regex match with parameter extraction
bot.action(/^user:(\d+):action:(ban|kick|warn)$/, async (ctx) => {
const userId = ctx.match[1];
const action = ctx.match[2];
await ctx.answerCallbackQuery(`Executed ${action} on user ${userId}`);
});Specialized Filters (Chat Types, Reactions, Boosts, Business, Forum)
import { Composer } from 'telegix';
// Filter by Chat Type: 'private', 'group', 'supergroup', 'channel'
bot.use(Composer.chatType('private', async (ctx, next) => {
console.log('Update came from a private DM!');
return next();
}));
// Filter by Message Reactions
bot.use(Composer.reaction(async (ctx, next) => {
console.log('User reacted with:', ctx.messageReaction.new_reaction);
return next();
}));
// Filter by Telegram Business Connection
bot.use(Composer.business(async (ctx, next) => {
console.log('Business message received');
return next();
}));
// Filter Forum Supergroups
bot.use(Composer.forum(async (ctx, next) => {
console.log('Forum topic message received');
return next();
}));🎛️ Fluent Keyboard & Markup Builder (Markup)
Construct reply and inline keyboards cleanly with Markup.
Custom Reply Keyboards
import { Markup } from 'telegix';
// Create a customized reply keyboard
const keyboard = Markup.keyboard([
['🛒 Shop', '📦 Orders'],
['📞 Support', '⚙️ Settings'],
])
.resize() // Compact button sizes
.oneTime() // Hide keyboard after first selection
.placeholder('Select an option...')
.selective(); // Show only to specific mentioned users
await ctx.reply('Main Menu:', keyboard);Inline Keyboards
const inline = Markup.inlineKeyboard([
[
Markup.button.callback('👍 Like', 'action_like'),
Markup.button.callback('👎 Dislike', 'action_dislike'),
],
[
Markup.button.url('🌐 Visit Website', 'https://telegix.dev'),
Markup.button.copyText('📋 Copy Code', 'TELE-2026'),
],
[
Markup.button.webApp('🚀 Launch Mini App', 'https://miniapp.example.com'),
],
]);
await ctx.reply('Interactive Post:', inline);Complete Button Builder Reference
| Button Builder Method | Description |
|---|---|
| Markup.button.text(text) | Standard reply keyboard text button. |
| Markup.button.callback(text, data) | Inline button triggering a callback query with data. |
| Markup.button.url(text, url) | Inline button opening an external URL. |
| Markup.button.primary(text, dataOrUrl) | Primary (Blue) styled button for prominent calls to action (Bot API 9.4+). |
| Markup.button.danger(text, dataOrUrl) | Danger (Red) styled button for destructive actions (Bot API 9.4+). |
| Markup.button.success(text, dataOrUrl) | Success (Green) styled button for positive confirmations (Bot API 9.4+). |
| Markup.button.colored(text, style, dataOrUrl) | Custom styled button with 'primary' \| 'danger' \| 'success' style. |
| Markup.button.webApp(text, url) | Button launching a Telegram Mini App. |
| Markup.button.copyText(text, textToCopy) | Inline button that copies textToCopy to the clipboard. |
| Markup.button.disabled(text) | Disabled, non-clickable button (Bot API 10.3). |
| Markup.button.login(text, url, options?) | Telegram Login URL authorization button. |
| Markup.button.switchToChat(text, query) | Inline button switching to chat with inline query. |
| Markup.button.switchToCurrentChat(text, query) | Inline button opening current chat with inline query. |
| Markup.button.pay(text) | Payment invoice button. |
| Markup.button.contactRequest(text) | Reply button requesting the user's phone number. |
| Markup.button.locationRequest(text) | Reply button requesting the user's GPS location. |
| Markup.button.pollRequest(text, type?) | Reply button requesting user to create a poll or quiz. |
| Markup.button.userRequest(text, reqId, options?) | Reply button requesting user selection. |
| Markup.button.botRequest(text, reqId, options?) | Reply button requesting bot selection. |
| Markup.button.groupRequest(text, reqId, options?) | Reply button requesting group chat selection. |
| Markup.button.channelRequest(text, reqId, options?) | Reply button requesting channel selection. |
🎨 Colored Buttons for Bots (Bot API 9.4+)
Telegram Bot API 9.4 introduced native visual styling for inline buttons, allowing developers to emphasize specific actions with colors:
primary: Emphasized primary button (accent/blue styling)danger: Destructive actions such as account deletion, bans, or cancelations (red styling)success: Confirmations, approvals, and checkout completions (green styling)
You can use colored buttons with callback queries or URLs via Markup.button or the RichMessage builder:
import { Markup, RichMessage } from 'telegix';
// 1. Using Markup.inlineKeyboard
bot.command('confirm_delete', async (ctx) => {
const keyboard = Markup.inlineKeyboard([
[
Markup.button.danger('🗑️ Delete Account', 'action_confirm_delete'),
Markup.button.primary('Keep Account', 'action_cancel'),
],
[
Markup.button.success('💳 Upgrade to Pro', 'https://example.com/checkout'),
],
]);
await ctx.reply('⚠️ Are you sure you want to delete your account permanently?', keyboard);
});
// 2. Using RichMessageBuilder
bot.command('order_status', async (ctx) => {
const message = RichMessage.card('📦 Order #98124', 'Order ready for dispatch')
.header('Delivery Status', '🚚')
.badge('Status', 'Pending Signature')
.row(
Markup.button.success('✅ Approve & Sign', 'approve_98124'),
Markup.button.danger('❌ Reject Order', 'reject_98124')
);
await ctx.replyWithRichMessage(message);
});Removing Keyboards & Force Reply
// Remove custom reply keyboard
await ctx.reply('Keyboard removed.', Markup.removeKeyboard());
// Force user to reply to this message
await ctx.reply('Please enter your email address:', Markup.forceReply());🌊 Streaming Text for Bots (streamText & streamDraft)
Real-time streaming is essential for modern AI-driven conversational bots (e.g. Gemini, OpenAI, Claude) and live progress updates. Telegix provides two powerful streaming modes:
- Real-Time Message Edit Streaming: Sends an initial placeholder message and progressively updates it with incoming chunks using an intelligent throttling buffer to safely prevent Telegram
429 Too Many Requestserrors. - Live Draft Streaming (Bot API 10.3+): Broadcasts ephemeral text chunks into the chat input bar via
sendMessageDraftas typing occurs, then sends the finalized message once the stream completes.
Real-Time Message Edit Streaming
import { Telegix, toTextStream } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
// Custom token generator simulation
async function* generateResponseTokens() {
const words = 'Telegix provides blazing fast, zero-dependency streaming for modern Telegram bots.'.split(' ');
for (const word of words) {
yield `${word} `;
await new Promise((resolve) => setTimeout(resolve, 150));
}
}
bot.command('generate', async (ctx) => {
// Directly stream onto chat via ctx.streamText
const result = await ctx.streamText(generateResponseTokens(), {
initialMessage: '💭 Generating your answer...',
intervalMs: 800, // Buffer updates to edit at most once every 800ms
minDeltaChars: 15, // Only edit if at least 15 new characters arrived
parse_mode: 'HTML',
});
console.log(`Stream complete! Final message ID: ${result.message_id}`);
});Live Draft Streaming (Bot API 10.3+)
Live drafts display real-time streamed text directly in the chat preview or input box without producing edit notifications:
bot.command('stream_draft', async (ctx) => {
async function* aiStream() {
yield 'Searching knowledge base...\n';
await new Promise((r) => setTimeout(r, 600));
yield 'Synthesizing response:\n';
await new Promise((r) => setTimeout(r, 600));
yield 'Everything is configured and running at optimal speeds!';
}
// Stream preview as draft, then send final message
await ctx.streamDraft(aiStream(), {
intervalMs: 600,
minDeltaChars: 10,
});
});Streaming AI & LLM Responses (Gemini, OpenAI, Generators)
Telegix automatically accepts any AsyncIterable, ReadableStream, Generator, Array, or String:
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
bot.command('ask', async (ctx) => {
if (!ctx.payload) {
return ctx.reply('Please provide a prompt! Example: /ask Explain quantum computing');
}
// Create Gemini streaming response
const responseStream = await ai.models.generateContentStream({
model: 'gemini-2.5-flash',
contents: ctx.payload,
});
// Convert Gemini chunks to text stream
async function* extractText(stream) {
for await (const chunk of stream) {
if (chunk.text) yield chunk.text;
}
}
await ctx.streamText(extractText(responseStream), {
initialMessage: '🤖 Thinking...',
intervalMs: 800,
minDeltaChars: 20,
parse_mode: 'HTML',
});
});💬 Asynchronous Conversations & Wizard Scenes
Interactive Inline Prompts (await ctx.prompt)
Ask sequential questions and await answers asynchronously directly inside your code:
import { Telegix, promptMiddleware } from 'telegix';
const bot = new Telegix(process.env.BOT_TOKEN);
bot.use(promptMiddleware());
bot.command('register', async (ctx) => {
// Step 1: Ask Name
const name = await ctx.prompt('What is your full name?');
// Step 2: Ask Age
const age = await ctx.prompt(`Nice to meet you, ${name}! How old are you?`, {
timeoutMs: 30000, // 30 seconds timeout
});
// Step 3: Confirmation
await ctx.reply(`🎉 Registration complete!\nName: ${name}\nAge: ${age}`);
});Multi-Step Wizard Scenes (WizardScene & Stage)
Build complex, multi-step conversation wizards with state tracking:
import { Telegix, WizardScene, Stage, session, Markup } from 'telegix';
// 1. Define Wizard Scene
const orderWizard = new WizardScene(
'pizza_order_wizard',
// Step 1: Select Flavor
async (ctx) => {
await ctx.reply(
'🍕 Step 1: Choose your pizza flavor:',
Markup.keyboard([['Margherita', 'Pepperoni'], ['Hawaiian', 'BBQ Chicken']]).resize()
);
return ctx.wizard.next();
},
// Step 2: Select Size
async (ctx) => {
ctx.wizard.state.flavor = ctx.message.text;
await ctx.reply(
`Selected: ${ctx.wizard.state.flavor}\nStep 2: Choose size:`,
Markup.keyboard([['Small', 'Medium', 'Large']]).resize()
);
return ctx.wizard.next();
},
// Step 3: Confirm & Finish
async (ctx) => {
ctx.wizard.state.size = ctx.message.text;
await ctx.reply(