telegram-bot-kit
v1.0.4
Published
A comprehensive Telegram Bot SDK for Node.js and Next.js
Maintainers
Readme
telegram-bot-kit
telegram-bot-kit is a lightweight, TypeScript-first SDK for building Telegram bots in Node.js and Next.js. Designed for serverless deployments (e.g., Vercel), it provides a simple, event-driven wrapper around the Telegram Bot API, enabling full control over messaging, media, interactions, and more.
Features
Core Messaging
- Send text messages with formatting, keyboards, and markup
- Edit, delete, and replace messages
- Handle callback queries and answer buttons
Media Support
- Send photos, audio, voice, animations, stickers, polls, venues, and contacts
- Upload files via URLs or local buffers/streams
- Download user-uploaded files
Interactive Elements
- Inline keyboards and reply keyboards
- Force reply and one-time keyboards
- Polls and venue sharing
Chat Management
- Forward messages
- Pin/unpin messages (single or all)
- Delete messages
Advanced Handling
- Full event-driven update processing (messages, callbacks, polls, payments, etc.)
- Inline query and chosen inline result support
- Error handling with descriptive API exceptions
- TypeScript interfaces for all Telegram structures
Deployment Ready
- Webhook-first design (no polling needed)
- ESM compatible (Node.js >=18)
- Lightweight with zero external runtime dependencies (uses only
cross-fetchfor HTTP)
Installation
npm install telegram-bot-kitQuick Start
Create a Bot: Talk to @BotFather and get your token.
Basic Usage:
import { TelegramBot } from 'telegram-bot-kit';
const bot = new TelegramBot('YOUR_BOT_TOKEN');- Handle Messages (Webhook Example):
import { createWebhookHandler } from 'telegram-bot-kit';
// In your server (e.g., Next.js API route)
const handler = createWebhookHandler(bot, 'YOUR_WEBHOOK_SECRET');
bot.on('message', (msg) => {
if (msg.text === '/start') {
bot.sendMessage(msg.chat.id, 'Hello! Welcome to telegram-bot-kit.');
}
});- Deploy: Set your webhook and deploy to Vercel!
Usage Examples
Sending Messages with Options
// Simple text
await bot.sendMessage(chatId, 'Hello World!');
// With inline keyboard
const keyboard = {
inline_keyboard: [
[{ text: 'Yes', callback_data: 'yes' }, { text: 'No', callback_data: 'no' }]
]
};
await bot.sendMessage(chatId, 'Choose:', { reply_markup: keyboard });
// With reply keyboard
const replyMarkup = {
keyboard: [[{ text: 'Button 1' }, { text: 'Button 2' }]],
one_time_keyboard: true
};
await bot.sendMessage(chatId, 'Choose an option:', { reply_markup: replyMarkup });Media Sending
// Send photo from URL
await bot.sendPhoto(chatId, 'https://example.com/photo.jpg', 'Caption here');
// Upload audio file
const audioBuffer = fs.readFileSync('audio.mp3');
await bot.sendAudio(chatId, audioBuffer, 'Audio title', { duration: 120 });
// Send poll
await bot.sendPoll(chatId, 'What\'s your favorite?', ['Option 1', 'Option 2'], {
is_anonymous: false, allows_multiple_answers: true
});Handling Interactions
// Handle callbacks (button presses)
bot.on('callback_query', (query) => {
bot.answerCallbackQuery(query.id, 'Button clicked!');
bot.sendMessage(query.message.chat.id, `You chose: ${query.data}`);
});
// Handle location requests
bot.on('message', (msg) => {
if (msg.location) {
const { latitude, longitude } = msg.location;
bot.sendVenue(msg.chat.id, latitude, longitude, 'Your Location', 'Address here');
}
});
// Inline queries (when users @mention your bot)
bot.on('inline_query', (query) => {
// Respond to user searches
bot.answerInlineQuery(query.id, [{
type: 'article',
id: '1',
title: 'Sample Result',
input_message_content: { message_text: 'Inline result!' }
}]);
});Editing and Deleting
// Send initial message
const msg = await bot.sendMessage(chatId, 'Initial text');
const messageId = msg.result.message_id;
// Edit text
await bot.editMessageText(chatId, messageId, 'Updated text', { parse_mode: 'Markdown' });
// Delete after delay
setTimeout(() => bot.deleteMessage(chatId, messageId), 5000);File Downloads
// Get file info
const fileResponse = await bot.getFile('file_id_from_message');
const fileObj = fileResponse.result;
// Get download URL
const downloadUrl = bot.getFileDownloadUrl(fileObj);
// Download using fetch
const response = await fetch(downloadUrl);
const buffer = await response.arrayBuffer();
// Save or process bufferWebhook Setup (Next.js)
In api/telegram-webhook.ts:
import { TelegramBot, createWebhookHandler } from 'telegram-bot-kit';
const bot = new TelegramBot();
const handler = createWebhookHandler(bot, process.env.WEBHOOK_SECRET);
export default handler;Set webhook in your bot setup:
import { setWebhook } from 'telegram-bot-kit';
await setWebhook(token, { url: 'https://your-domain.com/api/telegram-webhook' });API Reference
TelegramBot Methods
Core Messaging
sendMessage(chatId, text, options?)
Send a text message with optional formatting, keyboards, etc.
// Simple message
await bot.sendMessage(chatId, 'Hello World!');
// With Markdown formatting
await bot.sendMessage(chatId, 'Hello **world**!', { parse_mode: 'Markdown' });
// With inline keyboard
await bot.sendMessage(chatId, 'Choose an option:', {
reply_markup: {
inline_keyboard: [
[{ text: 'Yes', callback_data: 'yes_action' }, { text: 'No', callback_data: 'no_action' }]
]
}
});
// With reply keyboard
await bot.sendMessage(chatId, 'Select:', {
reply_markup: {
keyboard: [[{ text: 'Option 1' }, { text: 'Option 2' }]],
one_time_keyboard: true
}
});
// Disable notifications
await bot.sendMessage(chatId, 'Silent message', { disable_notification: true });editMessageText(chatId, messageId, text, options?)
Edit an existing text message.
const msg = await bot.sendMessage(chatId, 'Initial text');
const messageId = msg.result.message_id;
await bot.editMessageText(chatId, messageId, 'Updated text', { parse_mode: 'HTML' });editMessageCaption(chatId, messageId, caption?, options?)
Edit a message's caption.
await bot.editMessageCaption(chatId, messageId, 'New caption', { parse_mode: 'Markdown' });deleteMessage(chatId, messageId)
Delete a message.
await bot.deleteMessage(chatId, messageId);Keyboard & Interactions
answerCallbackQuery(callbackQueryId, options?)
Answer a callback query from an inline keyboard.
bot.on('callback_query', async (query) => {
await bot.answerCallbackQuery(query.id, {
text: 'Processing your choice...',
show_alert: false
});
});editMessageReplyMarkup(chatId, messageId, replyMarkup)
Edit a message's inline keyboard markup.
await bot.editMessageReplyMarkup(chatId, messageId, {
inline_keyboard: [[{ text: 'New Button', callback_data: 'new_action' }]]
});sendInlineButtons(chatId, text, rows, opts?)
Send a message with inline keyboard (convenience method).
await bot.sendInlineButtons(chatId, 'Choose action:', [
[{ text: 'Yes', callback_data: 'yes' }, { text: 'No', callback_data: 'no' }],
[{ text: 'Maybe', callback_data: 'maybe' }]
]);sendButtons(chatId, text, rows, resizeKeyboard?, oneTimeKeyboard?)
Send a message with reply keyboard (convenience method).
await bot.sendButtons(chatId, 'Choose an option:', [
[{ text: 'Option 1' }, { text: 'Option 2' }],
[{ text: 'Cancel' }]
], true, false); // resize_keyboard: true, one_time_keyboard: falserequestPhoneNumber(chatId, prompt?)
Request user's phone number with a reply keyboard.
await bot.requestPhoneNumber(chatId, 'Please share your contact to continue.');
bot.on('contact', (contact) => {
console.log('Phone:', contact.contact?.phone_number);
});requestLocation(chatId, prompt?)
Request user's location with a reply keyboard.
await bot.requestLocation(chatId, 'Where are you?');
bot.on('location', (location) => {
console.log('Coords:', location.location?.latitude, location.location?.longitude);
});hideKeyboard(chatId, text?)
Hide/remove the custom keyboard for a user.
await bot.hideKeyboard(chatId, 'Keyboard hidden!');Media
sendPhoto(chatId, photo, caption?, options?)
Send a photo (URL, Buffer, or file path).
// From URL
await bot.sendPhoto(chatId, 'https://example.com/photo.jpg', 'Photo caption');
// From file (Node.js)
const photoBuffer = require('fs').readFileSync('photo.jpg');
await bot.sendPhoto(chatId, photoBuffer, 'Uploaded photo', { filename: 'my_photo.jpg' });sendAudio(chatId, audio, caption?, options?)
Send an audio file.
const audioBuffer = require('fs').readFileSync('song.mp3');
await bot.sendAudio(chatId, audioBuffer, 'Song title', {
duration: 180,
title: 'Track Name',
performer: 'Artist'
});sendVoice(chatId, voice, caption?, options?)
Send a voice message.
const voiceBuffer = require('fs').readFileSync('voice.ogg');
await bot.sendVoice(chatId, voiceBuffer, 'Voice note');sendAnimation(chatId, animation, caption?, options?)
Send an animation/GIF.
await bot.sendAnimation(chatId, 'https://example.com/animation.gif', 'Cute animation!');sendSticker(chatId, sticker, options?)
Send a sticker.
const stickerBuffer = require('fs').readFileSync('sticker.webp');
await bot.sendSticker(chatId, stickerBuffer);sendDocument(chatId, document, caption?, options?)
Send a document/file.
const fileBuffer = require('fs').readFileSync('document.pdf');
await bot.sendDocument(chatId, fileBuffer, 'Important document', {
filename: 'report.pdf'
});sendVideo(chatId, video, caption?, options?)
Send a video file.
const videoBuffer = require('fs').readFileSync('video.mp4');
await bot.sendVideo(chatId, videoBuffer, 'Video description');sendPoll(chatId, question, options, opts?)
Send a poll.
await bot.sendPoll(chatId, 'What\'s your favorite color?', ['Red', 'Blue', 'Green'], {
is_anonymous: false,
allows_multiple_answers: true,
correct_option_id: 1, // For quiz mode
explanation: 'Blue is the most popular!'
});sendVenue(chatId, latitude, longitude, title, address, opts?)
Send a venue/location.
await bot.sendVenue(chatId, 40.7128, -74.0060, 'New York City', 'Manhattan, NY');sendContact(chatId, phoneNumber, firstName, opts?)
Send a contact.
await bot.sendContact(chatId, '+1234567890', 'John Doe', {
last_name: 'Smith',
vcard: 'BEGIN:VCARD\\nVERSION:3.0\\nFN:John Doe\\nTEL:+1234567890\\nEND:VCARD'
});Chat Management
forwardMessage(chatId, fromChatId, messageId, opts?)
Forward a message from one chat to another.
await bot.forwardMessage(myChatId, originalChatId, messageId, {
disable_notification: true
});pinChatMessage(chatId, messageId, opts?)
Pin a message in a chat.
await bot.pinChatMessage(chatId, messageId, {
disable_notification: false
});unpinChatMessage(chatId, messageId)
Unpin a specific message.
await bot.unpinChatMessage(chatId, messageId);unpinAllChatMessages(chatId)
Unpin all pinned messages in a chat.
await bot.unpinAllChatMessages(chatId);Files
getFile(fileId)
Get file information and download path.
const fileResponse = await bot.getFile('file_id_from_message');
console.log('Download URL available at:', bot.getFileDownloadUrl(fileResponse.result));getFileDownloadUrl(file)
Generate a download URL for a file object.
const file = { file_path: 'path/to/file' };
const url = bot.getFileDownloadUrl(file);
// Use with fetch or display/downloadConvenience Methods
replaceMessage(chatId, messageId, text, opts?)
Alias for editMessageText (shorter name).
await bot.replaceMessage(chatId, messageId, 'New content');Update Handling
handleUpdate(update)
Process a Telegram update and emit appropriate events.
// In webhook handler
export async function POST(req) {
const update = await req.json();
bot.handleUpdate(update);
return new Response('OK');
}Utility Functions (Outside TelegramBot Class)
setWebhook(token, options)
Set or delete a webhook for your bot.
import { setWebhook } from 'telegram-bot-kit';
await setWebhook('your_bot_token', {
url: 'https://yourapp.com/webhook',
secret_token: 'secret_for_webhooks',
max_connections: 100,
allowed_updates: ['message', 'callback_query']
});
// To remove webhook (delete)
await setWebhook('your_bot_token', { url: '' });createWebhookHandler(bot, secret?)
Create a request handler for processing Telegram webhooks.
import { createWebhookHandler } from 'telegram-bot-kit';
const webhookHandler = createWebhookHandler(bot, 'your_secret_token');
// Express.js example
app.post('/telegram-webhook', webhookHandler);
// Next.js API route
export default webhookHandler;Update Handling
handleUpdate(update)
Process a Telegram update and emit appropriate events.
// In webhook handler
export async function POST(req) {
const update = await req.json();
bot.handleUpdate(update);
return new Response('OK');
}Utility Functions (Outside TelegramBot Class)
setWebhook(token, options)
Set or delete a webhook for your bot.
import { setWebhook } from 'telegram-bot-kit';
await setWebhook('your_bot_token', {
url: 'https://yourapp.com/webhook',
secret_token: 'secret_for_webhooks',
max_connections: 100,
allowed_updates: ['message', 'callback_query']
});
// To remove webhook (delete)
await setWebhook('your_bot_token', { url: '' });createWebhookHandler(bot, secret?)
Create a request handler for processing Telegram webhooks.
import { createWebhookHandler } from 'telegram-bot-kit';
const webhookHandler = createWebhookHandler(bot, 'your_secret_token');
// Express.js example
app.post('/telegram-webhook', webhookHandler);
// Next.js API route
export default webhookHandler;Events
All events receive the corresponding Telegram object as the first parameter.
Message Events
(Triggered by user actions like sending messages; use with sendMessage method)
message - User sent a message, photo, document, etc.
bot.on('message', (msg) => {
if (msg.text === '/start') {
bot.sendMessage(msg.chat.id, 'Welcome!');
}
});edited_message - User edited a message
bot.on('edited_message', (msg) => {
bot.sendMessage(msg.chat.id, 'Message edited!');
});channel_post - New post in channel
bot.on('channel_post', (msg) => {
console.log('New channel post:', msg.text);
});edited_channel_post - Edited channel post
bot.on('edited_channel_post', (msg) => {
console.log('Channel post edited:', msg.text);
});Interaction Events
callback_query - User pressed an inline keyboard button
bot.on('callback_query', async (query) => {
await bot.answerCallbackQuery(query.id, 'Button clicked!');
await bot.sendMessage(query.message.chat.id, `You chose: ${query.data}`);
});inline_query - User typed @bot and is searching
bot.on('inline_query', async (query) => {
const results = [
{ type: 'article', id: '1', title: 'Result 1', input_message_content: { message_text: 'Content 1' } }
];
await bot.answerInlineQuery(query.id, results);
});chosen_inline_result - User selected an inline result
bot.on('chosen_inline_result', (result) => {
console.log('User chose:', result.result_id);
});Location/Contact Events
contact - User shared contact
bot.on('contact', (contact) => {
console.log('Phone:', contact.contact?.phone_number, 'Name:', contact.contact?.first_name);
});location - User shared location
bot.on('location', (location) => {
const { latitude, longitude } = location.location!;
bot.sendMessage(location.chat.id, `Your coords: ${latitude}, ${longitude}`);
});Payment Events (for payment bots)
shipping_query - User selected shipping option
bot.on('shipping_query', async (query) => {
// Answer with shipping options
});pre_checkout_query - User is about to pay
bot.on('pre_checkout_query', async (query) => {
// Validate payment (ok: true/false)
});Poll Events
poll - Poll was updated
bot.on('poll', (poll) => {
console.log('Poll updated:', poll.question, 'Total votes:', poll.total_voter_count);
});poll_answer - User voted in poll
bot.on('poll_answer', (answer) => {
console.log('User voted options:', answer.option_ids);
});Admin Events
my_chat_member - Bot's membership status changed
bot.on('my_chat_member', (update) => {
console.log('Bot membership changed:', update.new_chat_member.status);
});chat_member - Another member's status changed
bot.on('chat_member', (update) => {
console.log(update.new_chat_member.user.first_name, 'is now', update.new_chat_member.status);
});chat_join_request - User requested to join private group/channel
bot.on('chat_join_request', (request) => {
// Approve or decline join request
console.log(request.from.first_name, 'wants to join', request.chat.title);
});Options Object
Most methods accept an options object for parameters like:
parse_mode: 'Markdown' | 'HTML' | 'MarkdownV2'disable_notification: booleanreply_markup: Inline or reply keyboard- And more per Telegram API docs.
TypeScript Support
Full type safety with interfaces for:
Message,User,Chat,Update,CallbackQuery, etc.- Import from
telegram-bot-kitfor direct use.
Error Handling
Methods throw Error with Telegram's API description on failure. Wrap calls in try-catch:
try {
await bot.sendMessage(chatId, 'Test');
} catch (error) {
console.error('API Error:', error.message);
}Environment Variables
TELEGRAM_BOT_TOKEN: Bot token (can also pass directly to constructor)
Change Log
v1.0.3
- Fixed Next.js build failures by replacing
node-fetchwithcross-fetchfor isomorphic HTTP support, enabling client-side bundling compatibility.
License
TELEGRAM_BOT_TOKEN: Bot token (can also pass directly to constructor)
License
MIT
Contributing
Fork and submit PRs. For major changes, open an issue first.
Built for simplicity, power, and serverless compatibility!
