Telegram punya salah satu Bot API paling ramah developer di dunia — kamu bisa membuat bot untuk reminder, notifikasi server, polling, hingga integrasi dengan layananmu sendiri secara gratis. Di tutorial ini kita akan membangun bot Telegram dari nol memakai Python dan library resmi python-telegram-bot (PTB), lalu mempelajari cara menjalankannya 24 jam dengan webhook. Jika Python belum terpasang di komputermu, siapkan dulu lewat panduan cara install Python.

Apa Itu python-telegram-bot dan Kenapa Memilihnya?

python-telegram-bot adalah library Python paling populer untuk membuat bot Telegram, dengan lebih dari 25 ribu bintang di GitHub. Sejak versi 20, library ini sepenuhnya dibangun di atas asyncio, sehingga bot bisa menangani banyak pesan sekaligus tanpa saling memblokir. Ada alternatif lain seperti aiogram, tetapi PTB menonjol berkat dokumentasinya yang sangat lengkap, sistem handler yang rapi, serta dukungan fitur penuh mulai dari polling, webhook, sampai job queue untuk penjadwalan.

Langkah 1 — Membuat Bot Baru di BotFather

Sebelum menulis kode, kita perlu mendaftarkan bot ke Telegram supaya mendapat token — semacam kunci API yang mengidentifikasi bot kita. Langkahnya:

  1. Buka Telegram, lalu cari akun @BotFather (akun resmi untuk mengelola bot).
  2. Kirim perintah /newbot.
  3. Masukkan nama bot, misalnya BengkelKodeBot.
  4. Masukkan username unik yang diakhiri bot, misalnya bengkelkode_demo_bot.
  5. BotFather akan membalas dengan token yang tampak seperti 123456789:AAF...xyz. Simpan token ini baik-baik.

Jangan pernah menaruh token bot di repositori publik seperti GitHub atau GitLab. Siapa pun yang memegang token bisa mengendalikan bot-mu. Gunakan variabel environment atau file .env yang tidak ikut di-commit.

Langkah 2 — Menyiapkan Proyek dan Menginstal Dependensi

Buat folder proyek, lalu aktifkan virtual environment agar dependensi bot tidak bentrok dengan proyek lain. Instal python-telegram-bot dengan ekstra job-queue agar nanti bisa memakai fitur penjadwalan:

bash
mkdir telegram-bot && cd telegram-bot
python -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate
pip install "python-telegram-bot[job-queue]"

Setelah instalasi selesai, cek versinya dengan python -c 'import telegram; print(telegram.__version__)'. Jika muncul angka versi (misalnya 21.x), berarti library sudah siap dipakai.

Langkah 3 — Bot Echo Pertamamu

Mari mulai dengan bot paling sederhana: bot yang membalas pesan apa pun yang dikirim pengguna. Simpan kode berikut sebagai bot.py:

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

TOKEN = "GANTI_DENGAN_TOKEN_BOT_KAMU"


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # Menyambut pengguna saat mengetik /start
    await update.message.reply_text(
        "Halo! Aku bot BengkelKode. Kirim pesan apa saja, aku akan membalasnya."
    )


async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # Membalas pesan teks apa pun yang bukan command
    await update.message.reply_text(f"Kamu menulis: {update.message.text}")


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

    # Handler untuk command /start
    app.add_handler(CommandHandler("start", start))
    # Handler untuk pesan teks biasa (bukan command)
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))

    print("Bot berjalan... tekan Ctrl+C untuk berhenti.")
    app.run_polling()


if __name__ == "__main__":
    main()

Jalankan dengan python bot.py, lalu buka bot-mu di Telegram dan kirim pesan — bot akan langsung membalas. Metode run_polling() membuat bot terus-menerus menanyakan (polling) ke server Telegram apakah ada pesan baru. Ini cocok untuk pengembangan lokal, tapi belum untuk produksi.

Saat mengembangkan, kamu bisa membuat token baru kapan saja dari BotFather dengan perintah /revoke lalu /newtoken jika tokenmu bocor atau ingin menggantinya.

Langkah 4 — Menambahkan Command Handler

Bot sungguhan biasanya punya beberapa perintah, bukan hanya /start. Kita tambahkan /help dan /kode yang membalas dengan contoh kode. Setiap perintah cukup didaftarkan lewat CommandHandler:

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

TOKEN = "GANTI_DENGAN_TOKEN_BOT_KAMU"


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Halo! Ketik /help untuk melihat daftar perintah.")


async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "Perintah yang tersedia:\n"
        "/start - menyapa bot\n"
        "/help  - menampilkan bantuan ini\n"
        "/kode  - menampilkan contoh kode Python"
    )


async def kode(update: Update, context: ContextTypes.DEFAULT_TYPE):
    contoh = "print('Halo, Dunia!')"
    await update.message.reply_text(f"<pre>{contoh}</pre>", parse_mode="HTML")


async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(f"Kamu menulis: {update.message.text}")


def main():
    app = Application.builder().token(TOKEN).build()
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("help", help_command))
    app.add_handler(CommandHandler("kode", kode))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
    app.run_polling()


if __name__ == "__main__":
    main()

Perhatikan parameter parse_mode="HTML" pada reply_text — ini memungkinkan kita mengirim teks dengan format HTML seperti <pre> dan <b>. Penting juga urutan pendaftaran handler: MessageHandler diletakkan paling akhir agar tidak ikut menangkap command yang sudah punya handler sendiri.

Langkah 5 — Inline Keyboard Interaktif

Supaya bot terasa lebih hidup, tambahkan inline keyboard — tombol yang muncul tepat di bawah pesan dan mengirim callback saat ditekan. Ini cocok untuk menu pilihan topik, polling, atau navigasi:

python
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes

TOKEN = "GANTI_DENGAN_TOKEN_BOT_KAMU"


async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
    keyboard = [
        [
            InlineKeyboardButton("Python", callback_data="python"),
            InlineKeyboardButton("JavaScript", callback_data="javascript"),
        ],
        [InlineKeyboardButton("Tutup", callback_data="tutup")],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    await update.message.reply_text(
        "Pilih topik yang ingin kamu pelajari:", reply_markup=reply_markup
    )


async def button(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()  # wajib, supaya tombol tidak 'loading' terus

    if query.data == "tutup":
        await query.edit_message_text("Menu ditutup.")
    else:
        await query.edit_message_text(f"Kamu memilih topik: {query.data}")


def main():
    app = Application.builder().token(TOKEN).build()
    app.add_handler(CommandHandler("menu", menu))
    app.add_handler(CallbackQueryHandler(button))
    app.run_polling()


if __name__ == "__main__":
    main()

Ketika pengguna menekan tombol, Telegram mengirim callback_query yang ditangani CallbackQueryHandler. Nilai query.data berisi string callback_data yang kita set di tombol, sehingga kita bisa menentukan aksi selanjutnya. Jangan lupa memanggil query.answer() di awal agar indikator loading di tombol berhenti.

Memahami Async/Await di Balik Bot

Mungkin kamu penasaran kenapa semua fungsi handler diawali async dan memakai await. Sejak versi 20, python-telegram-bot berjalan di atas event loop asyncio, sehingga saat satu pengguna masih menunggu balasan jaringan, bot tetap bisa melayani pengguna lain. Kalau kamu belum familier dengan konsep ini, pelajari dulu lewat panduan lengkap async/await dan asyncio di Python — pemahaman ini akan membuatmu jauh lebih mudah men-debug bot.

Menangani Error dan Logging

Bot yang berjalan lama pasti sesekali menemui error, misalnya pesan yang dihapus sebelum dibalas atau batas rate-limit Telegram. Daripada bot berhenti diam-diam, tangkap semua error dengan error_handler dan catat ke log:

python
import logging
from telegram import Update
from telegram.ext import Application, ContextTypes

logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    level=logging.INFO,
)
logger = logging.getLogger(__name__)

TOKEN = "GANTI_DENGAN_TOKEN_BOT_KAMU"


async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE):
    logger.error("Terjadi kesalahan saat memproses update:", exc_info=context.error)


def main():
    app = Application.builder().token(TOKEN).build()
    app.add_error_handler(error_handler)
    app.run_polling()

Dengan logging.basicConfig, semua aktivitas bot dicatat ke konsol sehingga mudah ditelusuri. Untuk pendekatan logging yang lebih lengkap — level, format, dan penulisan ke file — baca panduan logging di Python.

Langkah 6 — Deploy 24 Jam dengan Webhook (FastAPI)

run_polling() hanya berjalan selama komputermu menyala. Agar bot aktif 24 jam, gunakan webhook: Telegram akan mendorong setiap update ke URL HTTPS milikmu, dan server-mu yang memprosesnya. Berikut contoh memakai FastAPI:

python
from contextlib import asynccontextmanager

from fastapi import FastAPI, Request
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes

TOKEN = "GANTI_DENGAN_TOKEN_BOT_KAMU"
WEBHOOK_URL = "https://contoh-kamu.com/webhook"

bot_app = Application.builder().token(TOKEN).build()


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Halo dari webhook!")


bot_app.add_handler(CommandHandler("start", start))


@asynccontextmanager
async def lifespan(app: FastAPI):
    await bot_app.initialize()
    await bot_app.bot.set_webhook(WEBHOOK_URL)
    yield
    await bot_app.bot.delete_webhook()
    await bot_app.shutdown()


app = FastAPI(lifespan=lifespan)


@app.post("/webhook")
async def webhook(request: Request):
    data = await request.json()
    update = Update.de_json(data, bot_app.bot)
    await bot_app.process_update(update)
    return {"status": "ok"}
bash
pip install fastapi uvicorn
uvicorn main:app --host 0.0.0.0 --port 8000

Telegram mewajibkan webhook memakai HTTPS dengan sertifikat valid, jadi deploy kode ini ke platform seperti Railway, Fly.io, atau VPS di balik reverse proxy. Jika kamu baru pertama kali membangun API dengan FastAPI, mulailah dari tutorial membuat REST API dengan FastAPI.

Jangan menjalankan polling dan webhook secara bersamaan di bot yang sama — keduanya akan berebut update dan menyebabkan konflik. Pilih salah satu: polling untuk pengembangan lokal, webhook untuk produksi.

Kesimpulan

Selamat! Kamu sudah membangun bot Telegram fungsional dengan Python — dari mendaftarkan bot di BotFather, echo bot, command handler, inline keyboard, logging, hingga deploy webhook dengan FastAPI. Dari fondasi ini, kamu bisa mengembangkannya lebih jauh: integrasi database untuk menyimpan data pengguna, job queue untuk pengingat terjadwal, atau menghubungkan bot ke AI assistant. Selamat bereksperimen!

Apakah membuat bot Telegram dengan python-telegram-bot gratis?

Ya, sepenuhnya gratis. Telegram menyediakan Bot API secara gratis tanpa biaya berlangganan, dan library python-telegram-bot bersifat open source di bawah lisensi LGPLv3. Satu-satunya biaya yang mungkin muncul adalah biaya server jika kamu men-deploy bot dengan webhook di layanan berbayar.

Apa perbedaan antara polling dan webhook?

Polling membuat bot terus-menerus bertanya ke server Telegram apakah ada pesan baru, cocok untuk pengembangan lokal. Webhook sebaliknya: server Telegram yang mengirim update ke URL milikmu, lebih hemat resource dan ideal untuk produksi, tetapi membutuhkan URL HTTPS yang bisa diakses publik.

Bagaimana cara menyimpan token bot agar tetap aman?

Simpan token di variabel environment atau file .env yang tidak ikut di-commit ke repositori, lalu baca lewat os.getenv atau library seperti python-dotenv. Jangan pernah menulis token langsung di kode yang di-push ke GitHub, karena token yang bocor bisa disalahgunakan orang lain.