Copy‑paste friendly snippets. Each block shows the command name, example code, and usage notes.
Tip: Replace placeholders like <TOKEN>, IDs, and URLs as needed.
ctx (and Markup if exposed by the platform). Prefer URL buttons over callback buttons since per‑command code can’t register global handlers.// Command: /start
ctx.reply('👋 Welcome to RunMyBot! Use /help to see what I can do.');
// Command: /help
ctx.replyWithMarkdown('*Try:*
/info – your profile
/photo – random image
/poll – quick poll
/dice – roll a dice');
// Command: /menu
ctx.reply('Choose an option:', Markup.inlineKeyboard([
[Markup.button.url('🌐 Website','https://runmybot.example')],
[Markup.button.url('📚 Docs','https://runmybot.example/docs')],
[Markup.button.url('🆘 Support','https://t.me/your_support_channel')]
]));
// Command: /info
const u = ctx.from;
ctx.replyWithMarkdown(`*User*
ID: ${u.id}
Name: ${u.first_name} ${u.last_name||''}
Username: @${u.username||'none'}`);
// Command: /echo your text here
const txt = (ctx.message.text||'').split(' ').slice(1).join(' ');
ctx.reply(txt || 'Nothing to echo.');
// Command: /photo
ctx.replyWithPhoto({ url:'https://picsum.photos/640/360' }, { caption:'Random 📸' });
// Command: /poll
ctx.replyWithPoll('Favorite stack?', ['MERN','MEAN','Django','Laravel'], { is_anonymous:false });
// Command: /dice
ctx.replyWithDice();
// Command: /contact
ctx.replyWithContact('+911234567890','Support','RunMyBot');
// Command: /whoami
ctx.reply('```
' + JSON.stringify(ctx.update, null, 2) + '
```', { parse_mode:'MarkdownV2' });
bot.action() or multi‑step wizards aren’t registered. Use URL buttons, force‑reply prompts, or separate commands instead.// file: index.js
// npm i telegraf
const { Telegraf, Markup } = require('telegraf');
const bot = new Telegraf(process.env.BOT_TOKEN || '');
bot.start((ctx) => ctx.reply('👋 Welcome! Use /help to see commands.'));
bot.help((ctx) => ctx.reply('Try /menu, /photo, /dice, /poll, /echo ...'));
// Health ping (optional)
bot.command('ping', (ctx) => ctx.reply('pong'));
bot.launch();
// Enable graceful stop
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));
BOT_TOKEN. On Render/Vercel with webhook, use the webhook example below.// Command: /start
ctx.reply('Hello 👋, welcome to RunMyBot!');
// Command: /help
ctx.replyWithMarkdown('*Commands:*\n/start – greet\n/info – user info\n/echo – echo back\n/menu – inline menu');
// Command: /info
const u = ctx.from;
ctx.replyWithMarkdown(`*User Info*\n- ID: ${u.id}\n- Name: ${u.first_name} ${u.last_name||''}\n- Username: @${u.username||'none'}`);
// Command: /echo
// Usage: /echo your message
const text = ctx.message.text.split(' ').slice(1).join(' ');
ctx.reply(text || 'Nothing to echo.');
// Command: /md
ctx.replyWithMarkdown('*Bold* _Italic_ `Code`\n[Link](https://t.me)');
// Command: /html
ctx.replyWithHTML('Bold Italic Code');
// Command: /typing
await ctx.sendChatAction('typing');
setTimeout(() => ctx.reply('Done typing…'), 1200);
// Command: /delete
try { await ctx.deleteMessage(); } catch (e) { ctx.reply('I cannot delete this.'); }
// Command: /photo
ctx.replyWithPhoto({ url: 'https://picsum.photos/640/360' }, { caption: 'Random image' });
// Command: /video
ctx.replyWithVideo({ url: 'https://file-examples.com/storage/fe1.mp4' });
// Command: /audio
ctx.replyWithAudio({ url:'https://file-examples.com/storage/fe1.mp3' }, { title:'Sample' });
// Command: /doc
ctx.replyWithDocument({ url:'https://file-examples.com/storage/fe1.pdf' });
// Command: /sticker
ctx.replyWithSticker('CAACAgUAAxkBAAIBQ2T…'); // replace with a real file_id
// Command: /menu
ctx.reply('Choose:', Markup.inlineKeyboard([
[Markup.button.callback('🔔 Notify', 'notify'), Markup.button.callback('❓ Help', 'help')],
[Markup.button.url('🌐 Website', 'https://runmybot.example')]
]));
// Handle callbacks
bot.action('notify', (ctx) => ctx.answerCbQuery('Enabled!'));
bot.action('help', (ctx) => ctx.editMessageText('Help opened.'));
// Command: /replykbd
ctx.reply('Pick one:', Markup.keyboard([
['⭐ Star', '📜 Help'],
['ℹ️ Info']
]).resize());
// Command: /hidekbd
ctx.reply('Keyboard hidden.', Markup.removeKeyboard());
// Command: /force
ctx.reply('What is your email?', { reply_markup: { force_reply: true } });
// Command: /dice
ctx.replyWithDice();
// Command: /poll
ctx.replyWithPoll('Favorite language?', ['JS','Python','Go'], { is_anonymous:false });
// Command: /quiz
ctx.replyWithQuiz('2 + 2 = ?', ['3','4','5'], { correct_option_id:1, explanation:'Basic math' });
// Command: /loc
ctx.replyWithLocation(21.1702, 72.8311); // Surat, IN
// Command: /venue
ctx.replyWithVenue(21.1702, 72.8311, 'RunMyBot HQ', 'Ring Road, Surat');
// Command: /contact
ctx.replyWithContact('+911234567890', 'Support', 'RunMyBot');
// Command: /album
ctx.replyWithMediaGroup([
{ type:'photo', media:{url:'https://picsum.photos/600/400?1'} },
{ type:'photo', media:{url:'https://picsum.photos/600/400?2'} },
]);
// Command: /caption
const sent = await ctx.replyWithPhoto({url:'https://picsum.photos/640/360'}, {caption:'Old'});
await ctx.telegram.editMessageCaption(ctx.chat.id, sent.message_id, undefined, 'New caption');
// Command: /admins
const admins = await ctx.getChatAdministrators();
ctx.reply('Admins:\n' + admins.map(a => `• ${a.user.first_name}`).join('\n'));
// Command: /ban
if (!ctx.message.reply_to_message) return ctx.reply('Reply to a user to ban');
const uid = ctx.message.reply_to_message.from.id;
try { await ctx.banChatMember(uid); ctx.reply('User banned.'); }
catch(e){ ctx.reply('Failed: ' + e.message); }
// Command: /pin
if (!ctx.message.reply_to_message) return ctx.reply('Reply to pin');
try { await ctx.pinChatMessage(ctx.message.reply_to_message.message_id); ctx.reply('Pinned.'); }
catch(e){ ctx.reply('Failed: ' + e.message); }
// In main file (not inside a command)
bot.on('inline_query', async (ctx) => {
const q = ctx.inlineQuery.query || 'empty';
await ctx.answerInlineQuery([
{ type:'article', id:'1', title:'Echo', input_message_content:{ message_text:q } },
], { cache_time: 0 });
});
// Command: /pay
ctx.replyWithInvoice({
title: 'Pro Plan', description: 'RunMyBot Pro (1 month)',
payload: 'pro-001', provider_token: process.env.PAY_TOKEN || '',
currency: 'INR', prices: [{ label:'Subscription', amount: 49900 }],
});
bot.on('pre_checkout_query', (ctx) => ctx.answerPreCheckoutQuery(true));
bot.on('successful_payment', (ctx) => ctx.reply('✅ Payment received!'));
// npm i telegraf @telegraf/session
const { Scenes, session } = require('telegraf');
const askName = new Scenes.BaseScene('askName');
askName.enter((ctx) => ctx.reply('Your name?'));
askName.on('text', (ctx) => { ctx.scene.state.name = ctx.message.text; return ctx.scene.enter('askEmail'); });
const askEmail = new Scenes.BaseScene('askEmail');
askEmail.enter((ctx) => ctx.reply('Your email?'));
askEmail.on('text', (ctx) => {
ctx.scene.state.email = ctx.message.text;
ctx.reply(`Saved: ${ctx.scene.state.name} & ${ctx.scene.state.email}`);
return ctx.scene.leave();
});
const stage = new Scenes.Stage([askName, askEmail]);
bot.use(session());
bot.use(stage.middleware());
// Command: /register
ctx.scene.enter('askName');
// Global (top of file)
bot.use(async (ctx, next) => {
console.log('Update', ctx.updateType);
return next();
});
// Anywhere
bot.hears(/hello|hi/i, (ctx) => ctx.reply('Hello there!'));
async function onlyAdmins(ctx, next){
const me = await ctx.getChatMember(ctx.from.id);
if(['administrator','creator'].includes(me.status)) return next();
return ctx.reply('Admins only.');
}
// Command: /admin
onlyAdmins(ctx, () => ctx.reply('Secret admin thing…'));
// file: server.js
// npm i telegraf express body-parser
const { Telegraf } = require('telegraf');
const express = require('express');
const app = express();
const bot = new Telegraf(process.env.BOT_TOKEN || '');
app.use(bot.webhookCallback('/tg'));
bot.telegram.setWebhook((process.env.BASE_URL || 'https://example.com') + '/tg');
app.get('/', (_, res) => res.send('OK'));
app.listen(process.env.PORT || 3000, () => console.log('Webhook listening'));
// 1) Start + Menu
bot.start((ctx) => ctx.reply('Welcome! Ready to level up?', Markup.inlineKeyboard([
[Markup.button.callback('📬 Contact Support','support')],
[Markup.button.callback('💎 Go Pro (₹499)','pro')]
])));
// 2) Support flow – collect email
bot.action('support', async (ctx) => {
await ctx.answerCbQuery();
await ctx.reply('Your email?', { reply_markup:{ force_reply:true } });
});
bot.on('message', async (ctx, next) => {
if (ctx.message.reply_to_message && /Your email\?/i.test(ctx.message.reply_to_message.text)) {
const email = ctx.message.text.trim();
await ctx.reply(`Thanks! Ticket created for ${email}. Our team will reach out.`);
// TODO: save to DB / send to webhook
return;
}
return next();
});
// 3) Payment offer
bot.action('pro', async (ctx) => {
await ctx.answerCbQuery();
return ctx.replyWithInvoice({
title:'RunMyBot Pro', description:'1 month access', payload:'pro-001',
provider_token: process.env.PAY_TOKEN || '', currency:'INR',
prices:[{label:'Pro Plan', amount:49900}],
});
});
bot.on('pre_checkout_query', (ctx) => ctx.answerPreCheckoutQuery(true));
bot.on('successful_payment', (ctx) => ctx.reply('🎉 You are Pro now! Use /help to explore premium features.'));
// Command: /joke
const jokes = [
'Why don’t scientists trust atoms? Because they make up everything!',
'I would tell you a UDP joke, but you might not get it.'
];
ctx.reply(jokes[Math.floor(Math.random()*jokes.length)]);
// Command: /setcmds
await ctx.telegram.setMyCommands([
{ command:'start', description:'Start the bot' },
{ command:'help', description:'Get help' },
{ command:'info', description:'Your profile' },
]);
ctx.reply('Commands published.');
// Command: /forward
const targetChatId = ''; // e.g., your admin channel
if (!ctx.message.reply_to_message) return ctx.reply('Reply to a message to forward');
await ctx.telegram.forwardMessage(targetChatId, ctx.chat.id, ctx.message.reply_to_message.message_id);
ctx.reply('Forwarded.');
// Command: /whoami
ctx.reply('```\n' + JSON.stringify(ctx.update, null, 2) + '\n```', { parse_mode:'MarkdownV2' });
bot.launch() and set a fixed HTTPS URL.