Commands are how users interact with your Telegram bot. When a user sends /start, /help, or any custom command, your bot receives it and responds. This guide shows you how to add commands, handle messages, and create interactive buttons for your bot hosted on FPS.ms.
Prerequisites
Before adding commands, make sure you:
- Have your bot installed and running on FPS.ms
- Have created your bot with BotFather
- Have your bot token set up in a
.env file
Python (python-telegram-bot)
Basic commands
app.py
import os
from dotenv import load_dotenv
from telegram import Update
from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, filters, ContextTypes
load_dotenv()
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
await update.message.reply_text(f'Welcome, {user.first_name}! Type /help to see what I can do.')
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
help_text = (
'Here are my commands:\n'
'/start - Start the bot\n'
'/help - Show this message\n'
'/ping - Check if I am online\n'
'/echo <text> - I will repeat your text'
)
await update.message.reply_text(help_text)
async def ping(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text('Pong!')
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
if context.args:
await update.message.reply_text(' '.join(context.args))
else:
await update.message.reply_text('Usage: /echo <text>')
def main():
app = ApplicationBuilder().token(os.environ['BOT_TOKEN']).build()
app.add_handler(CommandHandler('start', start))
app.add_handler(CommandHandler('help', help_command))
app.add_handler(CommandHandler('ping', ping))
app.add_handler(CommandHandler('echo', echo))
print('Bot is running...')
app.run_polling()
if __name__ == '__main__':
main()
How it works
CommandHandler('start', start) — registers a handler for the /start command
context.args — contains the text after the command (e.g., /echo hello world gives ['hello', 'world'])
update.effective_user — the user who sent the message
app.run_polling() — starts listening for messages using polling
Handling regular messages
To respond to regular text messages (not commands), use
MessageHandler:
Message handler
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = update.message.text
await update.message.reply_text(f'You said: {text}')
# Add after your command handlers
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
Add interactive buttons to your messages:
Inline keyboard
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import CallbackQueryHandler
async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
keyboard = [
[InlineKeyboardButton('Option 1', callback_data='option_1')],
[InlineKeyboardButton('Option 2', callback_data='option_2')],
[InlineKeyboardButton('Visit FPS.ms', url='https://fps.ms')],
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text('Choose an option:', reply_markup=reply_markup)
async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
await query.edit_message_text(f'You selected: {query.data}')
# Register handlers
app.add_handler(CommandHandler('menu', menu))
app.add_handler(CallbackQueryHandler(button_callback))
Node.js (Telegraf)
Basic commands
index.js
require('dotenv').config();
const { Telegraf } = require('telegraf');
const bot = new Telegraf(process.env.BOT_TOKEN);
bot.start((ctx) => {
ctx.reply(`Welcome, ${ctx.from.first_name}! Type /help to see what I can do.`);
});
bot.help((ctx) => {
ctx.reply(
'Here are my commands:\n' +
'/start - Start the bot\n' +
'/help - Show this message\n' +
'/ping - Check if I am online\n' +
'/echo <text> - I will repeat your text'
);
});
bot.command('ping', (ctx) => {
ctx.reply('Pong!');
});
bot.command('echo', (ctx) => {
const text = ctx.message.text.split(' ').slice(1).join(' ');
if (text) {
ctx.reply(text);
} else {
ctx.reply('Usage: /echo <text>');
}
});
bot.launch();
console.log('Bot is running...');
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));
Handling regular messages
Message handler
bot.on('text', (ctx) => {
ctx.reply(`You said: ${ctx.message.text}`);
});
Handler order matters
Place the bot.on('text') handler after all your bot.command() handlers. Telegraf processes handlers in order, and you don't want the text handler to catch commands.
Inline keyboard
const { Markup } = require('telegraf');
bot.command('menu', (ctx) => {
ctx.reply('Choose an option:', Markup.inlineKeyboard([
[Markup.button.callback('Option 1', 'option_1')],
[Markup.button.callback('Option 2', 'option_2')],
[Markup.button.url('Visit FPS.ms', 'https://fps.ms')],
]));
});
bot.action('option_1', (ctx) => {
ctx.answerCbQuery();
ctx.editMessageText('You selected: Option 1');
});
bot.action('option_2', (ctx) => {
ctx.answerCbQuery();
ctx.editMessageText('You selected: Option 2');
});
Register commands in BotFather
After adding commands in your code, register them in BotFather so they appear in Telegram's command menu:
- Open @BotFather in Telegram
- Type
/setcommands
- Select your bot
- Send your commands:
start - Start the bot
help - Show available commands
ping - Check if the bot is online
echo - Repeat your text
menu - Show interactive menu
See the
BotFather guide for more details.
Python vs Node.js command handling
| Feature | Python (python-telegram-bot) | Node.js (Telegraf) |
|---|
| Command handler | `CommandHandler('ping', ping)` | `bot.command('ping', handler)` |
| Message handler | `MessageHandler(filters.TEXT, handler)` | `bot.on('text', handler)` |
| Get command args | `context.args` | `ctx.message.text.split(' ').slice(1)` |
| Reply to user | `update.message.reply_text()` | `ctx.reply()` |
| Inline keyboard | `InlineKeyboardMarkup` | `Markup.inlineKeyboard()` |
| Button callback | `CallbackQueryHandler` | `bot.action()` |
Troubleshooting
| Problem | Cause | Fix |
|---|
| Command not working | Handler not registered | Make sure you added the handler before `run_polling()` / `bot.launch()` |
| Bot doesn't respond to messages | Missing message handler or privacy mode | Add a `MessageHandler` / `bot.on('text')`, or disable privacy mode in BotFather with `/setprivacy` |
| Buttons not responding | Missing callback handler | Register a `CallbackQueryHandler` / `bot.action()` for each `callback_data` |
| "Conflict: terminated by other getUpdates request" | Multiple instances running | Make sure only one instance of your bot is running |
For more help, see our full
troubleshooting guide.
Next steps