Building a Telegram Bot with Claude API (Python, 2026)

A Telegram bot powered by Claude gives you a personal AI assistant accessible from your phone. In this tutorial you’ll build one from scratch — handling messages, keeping conversation history, and deploying it.


Prerequisites

  • Python 3.10+
  • Anthropic API key
  • Telegram account

Step 1: Create a Telegram Bot

1. Open Telegram, search for @BotFather 2. Send /newbot and follow the prompts 3. Copy the bot token (looks like 7123456789:AAF...)


Step 2: Install Dependencies

pip install python-telegram-bot anthropic

Step 3: Basic Echo Bot

from telegram import Update
from telegram.ext import Application, MessageHandler, filters, ContextTypes
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):     text = update.message.text     await update.message.reply_text(f"You said: {text}")
app = Application.builder().token(BOT_TOKEN).build() app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message)) app.run_polling()

Test it first — make sure messages echo back before adding Claude.


Step 4: Add Claude

from telegram import Update
from telegram.ext import Application, MessageHandler, CommandHandler, filters, ContextTypes
import anthropic
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN" claude = anthropic.Anthropic()
conversations: dict[int, list] = {}
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):     chat_id = update.effective_chat.id     user_text = update.message.text
if chat_id not in conversations:         conversations[chat_id] = []     conversations[chat_id].append({"role": "user", "content": user_text})
history = conversations[chat_id][-20:]
response = claude.messages.create(         model="claude-sonnet-4-6",         max_tokens=1024,         system="You are a helpful assistant. Be concise — this is a Telegram chat.",         messages=history,     )
reply = response.content[0].text     conversations[chat_id].append({"role": "assistant", "content": reply})     await update.message.reply_text(reply)
async def reset_command(update: Update, context: ContextTypes.DEFAULT_TYPE):     conversations.pop(update.effective_chat.id, None)     await update.message.reply_text("Conversation reset.")
app = Application.builder().token(BOT_TOKEN).build() app.add_handler(CommandHandler("reset", reset_command)) app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message)) app.run_polling()

Step 5: Add Typing Indicator

async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await context.bot.send_chat_action(chat_id=update.effective_chat.id, action="typing")
    # ... rest of handler

Step 6: Handle Long Responses

Telegram has a 4096-character limit. Split long responses:

def split_message(text: str, limit: int = 4000) -> list[str]:
    if len(text) <= limit:
        return [text]
    parts = []
    while text:
        parts.append(text[:limit])
        text = text[limit:]
    return parts

In your handler:

for part in split_message(reply): await update.message.reply_text(part)

Step 7: Deploy on a VPS

# /etc/systemd/system/claude-bot.service
[Unit]
Description=Claude Telegram Bot
After=network.target
[Service] User=ubuntu WorkingDirectory=/home/ubuntu/claude-bot ExecStart=/usr/bin/python3 bot.py Restart=always Environment=ANTHROPIC_API_KEY=your-key Environment=BOT_TOKEN=your-token
[Install] WantedBy=multi-user.target
sudo systemctl enable claude-bot
sudo systemctl start claude-bot

Cost Estimate

With 100 daily messages (avg 200 input + 150 output tokens each) on Sonnet:

  • Input: ~$0.06/day
  • Output: ~$0.23/day
  • Total: ~$9/month
Add prompt caching on the system prompt to cut input costs by ~90%.

What to Build Next

  • /summarize command — paste a URL, get a summary
  • Image analysis — handle filters.PHOTO and use Claude’s vision
  • Scheduled reminders — use job_queue from python-telegram-bot
  • Group chat mode — different system prompt for group vs private

Originally published at kalyna.pro