How to Build a Telegram Bot with Python (2026 Guide)

Reading time: 5 minutes

Last modified:

By the end of this tutorial you’ll have a working Telegram bot that responds to /start and /help, echoes messages back to the user, displays an inline keyboard, and runs on a VPS via webhook. All code is tested against python-telegram-bot 20.7 and the Telegram Bot API as of mid-2026.

What You’ll Build

A bot that handles /start, /help, and free-text echo — plus an inline keyboard with a callback handler. The same code runs in polling mode on your laptop for development, and switches to webhook mode for production.

Prerequisites

  • Python 3.10 or later
  • A Telegram account with access to @BotFather
  • Basic Python knowledge (functions, async/await)
  • A Linux VPS for the webhook steps (Hetzner Cloud CX11, $4/month, is sufficient)

Step 1: Create the Bot with BotFather

Open Telegram and start a chat with @BotFather.

  1. Send /newbot
  2. Enter a display name — e.g. My First Bot
  3. Enter a username ending in bot — e.g. myfirst_demo_bot
  4. BotFather replies with a token: 7123456789:AAHdqTcvCH1vGWJxfSeofSoK31HTXv9NMTU

Store this token as an environment variable, not in source code:

export TELEGRAM_TOKEN="7123456789:AAHdqTcvCH1vGWJxfSeofSoK31HTXv9NMTU"

Anyone with this token controls the bot. Treat it like an API key.

Step 2: Install python-telegram-bot v20

pip install "python-telegram-bot==20.7"

Version 20 rewrote the library around Python’s asyncio. The v13 patterns (Updater, synchronous handlers) no longer work. Every handler is now an async def function, and the entry point is Application instead of Updater.

Step 3: Basic Bot with Command Handlers

Create bot.py:

import os
import logging
from telegram import Update
from telegram.ext import (
    Application,
    CommandHandler,
    MessageHandler,
    filters,
    ContextTypes,
)

logging.basicConfig(level=logging.INFO)
TOKEN = os.environ["TELEGRAM_TOKEN"]


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text(
        "Hello! I'm your bot. Send /help to see what I can do."
    )


async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text(
        "/start — greeting\n"
        "/help — this message\n"
        "Any other text — I echo it back"
    )


async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text(update.message.text)


def main() -> None:
    app = Application.builder().token(TOKEN).build()

    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("help", help_command))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))

    app.run_polling()


if __name__ == "__main__":
    main()

Run it:

python bot.py

Open Telegram, find your bot by username, send /start. You’ll see the greeting within a second. Press Ctrl+C to stop.

run_polling() is fine for development — no public URL needed. For production, polling burns CPU and adds 1–3 seconds of latency. Use webhooks instead (Step 5).

Step 4: Inline Keyboard

Inline keyboards attach buttons directly to a message. Each button carries a callback_data string that Telegram sends back when the user taps it.

Add this to bot.py:

from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import CallbackQueryHandler


async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    keyboard = [
        [
            InlineKeyboardButton("Option A", callback_data="option_a"),
            InlineKeyboardButton("Option B", callback_data="option_b"),
        ]
    ]
    await update.message.reply_text(
        "Pick one:", reply_markup=InlineKeyboardMarkup(keyboard)
    )


async def handle_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    query = update.callback_query
    await query.answer()  # removes the loading spinner
    await query.edit_message_text(f"You picked: {query.data}")

Register both handlers in main():

app.add_handler(CommandHandler("menu", menu))
app.add_handler(CallbackQueryHandler(handle_button))

Send /menu to the bot — two buttons appear. Tapping either replaces the message text with your selection.

Step 5: Switch to Webhooks for Production

Polling works by sending getUpdates to Telegram every second. Webhooks flip the model: Telegram calls your server the moment a message arrives. This cuts latency to under 100 ms and drops CPU usage to near zero between messages.

Set the webhook manually:

curl "https://api.telegram.org/bot${TELEGRAM_TOKEN}/setWebhook?url=https://yourdomain.com/webhook"

Telegram confirms: {"ok":true,"result":true}.

Or use python-telegram-bot’s built-in server:

Replace app.run_polling() with:

app.run_webhook(
    listen="0.0.0.0",
    port=8443,
    url_path="/webhook",
    webhook_url="https://yourdomain.com/webhook",
    cert="cert.pem",       # only needed for self-signed TLS
)

Telegram requires HTTPS. Get a certificate from Let’s Encrypt (certbot) or put Cloudflare’s proxy in front of your VPS. Telegram accepts ports 443, 80, 88, and 8443.

Step 6: Deploy to a VPS

SSH into your server and set up the bot as a systemd service so it survives reboots and restarts on crash.

# On your VPS
mkdir -p /opt/mybot
scp bot.py user@yourserver:/opt/mybot/
ssh user@yourserver "pip3 install 'python-telegram-bot==20.7'"

Create /etc/systemd/system/mybot.service:

[Unit]
Description=My Telegram Bot
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/opt/mybot
Environment="TELEGRAM_TOKEN=7123456789:AAHdqTcvCH1vGWJxfSeofSoK31HTXv9NMTU"
ExecStart=/usr/bin/python3 /opt/mybot/bot.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable mybot
sudo systemctl start mybot
sudo systemctl status mybot

Verify the webhook is receiving traffic:

curl "https://api.telegram.org/bot${TELEGRAM_TOKEN}/getWebhookInfo"

The response shows pending_update_count — it should drop to 0 once the bot processes queued messages.

When to Upgrade to a Mini App

Bots handle text commands well, but hit walls fast: no multi-step forms, no rich product listings, no native payment UI without workarounds.

Telegram Mini Apps are web pages (HTML/CSS/JS or any framework) that open inside Telegram via a button tap. They get access to the Telegram user’s identity, Telegram Pay, and the Haptic Feedback API. The user never leaves the app.

A typical path: launch with a bot for commands and notifications, then open a Mini App for anything requiring a UI — checkout flow, appointment booking, a dashboard. The bot stays as the entry point and notification channel; the Mini App handles complex interaction.

Need a production Telegram bot or Mini App built for your business? CimpleO’s Telegram development team handles the full stack — bot logic, Mini App frontend, backend API, and Telegram Pay integration. Tell us what you’re building.

Часто задаваемые вопросы

Do I need a server to run a Telegram bot?

For polling mode: no, a local machine or a cheap VPS works. For webhook mode (recommended for production): yes, you need a server with a public HTTPS URL. A $5/month VPS on Hetzner or DigitalOcean is enough for most bots.

What's the difference between polling and webhooks?

Polling: your bot constantly asks Telegram 'any new messages?' Webhooks: Telegram pushes new messages to your server the moment they arrive. Webhooks are faster and use fewer resources — use them in production.

Can I run multiple bots on one server?

Yes. Each bot needs its own BotFather token and its own webhook URL path. You can run them in the same Python process or separate systemd services.

How do I keep my bot running after I close the terminal?

Use systemd on Linux: create a service file that starts your bot script on boot and restarts it on crash. Alternatively, use screen or tmux for quick deployments, or Docker for containerised setups.

What's the difference between a Telegram bot and a Mini App?

Bots operate through chat commands and messages. Mini Apps are web apps that run inside Telegram with a full UI — buttons, forms, payments. Bots are simpler to build; Mini Apps offer a richer UX. Most production products start with a bot and add a Mini App later.

CimpleO telegram
How to Build a Telegram Bot with Python (2026 Guide)
JUN 15 2026 · 5 MIN
Table of Contents