Skip to content

How to build a Telegram AI bot with Claude, GPT or Gemini

Create a Telegram bot in BotFather and answer messages with Claude, GPT or Gemini through an OpenAI-compatible API, with tested Python code and costs.

Updated November 1, 2026Markdown version

Create the bot in @BotFather to get its token, then run a short Python script that sends each message to a chat model and posts the answer back. With a 5abeer key, the OpenAI SDK reaches Claude, GPT and Gemini models below official prices, and you pay only for the tokens each answer uses.

What do you need to build a Telegram AI bot?#

  • A Telegram account, to create the bot in @BotFather and get its token.
  • A 5abeer API key for the provider the bot will use. The code below uses the default model, claude-sonnet-5.5, so it needs a Claude key. The steps are in Create a key, and the basics are in How to get an API key for Claude, GPT and Gemini.
  • Python 3.10 or later, with two packages: the official openai SDK and requests.
  • A computer or server that stays on while the bot runs.

How do you get a bot token from BotFather?#

  1. Start a new bot#

    Open a chat with @BotFather in Telegram and send /newbot.

  2. Pick a name and a username#

    The name is what people see in the chat. The username is the bot's address, as in t.me/username. It must be 5 to 32 characters long, use only Latin letters, digits and underscores, and end in bot, for example support_helper_bot.

  3. Copy the token#

    BotFather replies with the bot's token. Telegram's advice is direct: "Keep your token secure and store it safely, it can be used by anyone to control your bot." If the token leaks, send /token to BotFather to generate a new one.

How do you connect the bot to Claude, GPT or Gemini?#

5abeer speaks the OpenAI Chat Completions format, so the bot uses the official OpenAI SDK with two changes: the base URL and the key. The same code reaches Claude, GPT and Gemini models. Only the model id and the key's provider change. Moving from another OpenAI-compatible service is the same switch, as in An OpenRouter alternative below official prices.

OpenAI-compatiblehttps://api.5abeer.ai/v1Authorization: Bearer <KEY>
Anthropic-compatiblehttps://api.5abeer.aix-api-key: <KEY>
Geminihttps://api.5abeer.ai/v1betax-goog-api-key: <KEY>

Before running the bot, send one test request with your key. If it answers, the key and the model are ready. The format is explained in Chat Completions.

curl --request POST "https://api.5abeer.ai/v1/chat/completions" \
  --header "Authorization: Bearer $KHABEER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"model":"claude-sonnet-5.5","messages":[{"role":"user","content":"Write a product idea in one sentence."}]}'
Response
{
  "id": "chatcmpl-9f2",
  "object": "chat.completion",
  "model": "claude-sonnet-5.5",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I help you today?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 21,
    "completion_tokens": 12,
    "total_tokens": 33
  }
}

The key is read from KHABEER_API_KEY, so it never appears in your code.

What does the full bot look like?#

The whole bot is one Python file. It uses long polling, so it needs no domain, certificate or open port. It answers only the chats you allow.

bot.py
import os
import time

import requests
from openai import OpenAI

TELEGRAM = "https://api.telegram.org/bot" + os.environ["TELEGRAM_BOT_TOKEN"]
client = OpenAI(api_key=os.environ["KHABEER_API_KEY"], base_url="https://api.5abeer.ai/v1")
MODEL = os.environ.get("BOT_MODEL", "claude-sonnet-5.5")
# Chat ids that may use the bot, comma-separated. "*" opens it to everyone.
ALLOWED = {x.strip() for x in os.environ.get("ALLOWED_CHAT_IDS", "").split(",") if x.strip()}

SYSTEM = "You are a helpful assistant. Answer briefly, in plain text, in the user's language."
GREETING = "Hi! Send me a question"
SORRY = "Sorry, I could not answer right now. Try again in a minute"
MAX_HISTORY = 10  # messages kept per chat: the last 5 questions and answers
history = {}


def telegram(method, **params):
    r = requests.post(f"{TELEGRAM}/{method}", json=params, timeout=60)
    r.raise_for_status()
    return r.json()["result"]


def send(chat_id, text):
    # Telegram accepts up to 4096 characters per message, so long answers go in parts.
    for i in range(0, len(text), 4000):
        telegram("sendMessage", chat_id=chat_id, text=text[i : i + 4000])


def handle(message):
    chat_id = message["chat"]["id"]
    text = message.get("text")
    if not text:
        return
    if "*" not in ALLOWED and str(chat_id) not in ALLOWED:
        print(f"ignored chat {chat_id}: add it to ALLOWED_CHAT_IDS")
        return
    if text.startswith(("/start", "/reset")):
        history.pop(chat_id, None)
        send(chat_id, GREETING)
        return
    telegram("sendChatAction", chat_id=chat_id, action="typing")
    past = history.get(chat_id, [])
    question = {"role": "user", "content": text}
    try:
        reply = client.chat.completions.create(
            model=MODEL,
            messages=[{"role": "system", "content": SYSTEM}, *past, question],
            max_tokens=1000,
        )
        answer = (reply.choices[0].message.content or "").strip()
    except Exception as error:
        print(f"model error: {error}")
        answer = ""
    if not answer:
        send(chat_id, SORRY)
        return
    history[chat_id] = (past + [question, {"role": "assistant", "content": answer}])[-MAX_HISTORY:]
    send(chat_id, answer)


def main():
    offset = 0
    while True:
        try:
            updates = telegram("getUpdates", offset=offset, timeout=50, allowed_updates=["message"])
        except requests.RequestException as error:
            print(f"telegram error: {error}")
            time.sleep(5)
            continue
        for update in updates:
            offset = update["update_id"] + 1
            if "message" in update:
                try:
                    handle(update["message"])
                except Exception as error:
                    print(f"update {update['update_id']} failed: {error}")


if __name__ == "__main__":
    main()

We tested this file on 2026-11-01 with Python 3.11 and the openai SDK 2.32 and 3.42, against local stand-ins for Telegram and the API, using a fake token and key.

How do you run it and keep strangers out?#

Anyone who finds the bot's username can message it, and every answer is paid from your balance. That is why the bot answers only the chat ids listed in ALLOWED_CHAT_IDS, and nobody when the list is empty.

macOS / Linux
pip install openai requests
export TELEGRAM_BOT_TOKEN="YOUR_BOT_TOKEN"
export KHABEER_API_KEY="YOUR_5ABEER_API_KEY"
python3 bot.py
Windows
pip install openai requests
$env:TELEGRAM_BOT_TOKEN="YOUR_BOT_TOKEN"
$env:KHABEER_API_KEY="YOUR_5ABEER_API_KEY"
python bot.py
  1. Start the bot and send it any message from your Telegram account.
  2. The terminal prints ignored chat 123456789: add it to ALLOWED_CHAT_IDS with your real chat id.
  3. Stop the bot, set ALLOWED_CHAT_IDS to that id the same way you set the key, and start it again.

Separate several ids with commas. The value * opens the bot to everyone, so set a spend limit on the key first.

How does the code work?#

  • Long polling: getUpdates waits up to 50 seconds for new messages. The offset tells Telegram which updates are already handled, so none is answered twice.
  • Typing status: Telegram shows it for up to 5 seconds, or until the reply arrives.
  • Memory: the bot keeps the last 10 messages of each chat and sends them with every question, so follow-up questions work. /start or /reset clears that chat's memory, and so does a restart.
  • Long answers: Telegram accepts 4,096 characters per message, so the bot sends longer answers in parts of 4,000.
  • Plain text: the bot sets no parse_mode, and the system prompt asks for plain text, so answers rarely show stray Markdown symbols.
  • Errors: the SDK retries rate limits, timeouts and server errors twice on its own. If a request still fails, the bot logs the error and sends a short apology instead of stopping.
  • max_tokens=1000 caps the answer length for Claude and Gemini models. GPT models ignore it, as listed in Parameters.

How do you keep the bot running?#

Long polling needs only outgoing connections, so any machine that stays on will do: a small cloud server, a home server or a container. Run it under a service manager such as systemd, or give the container a restart policy, so the bot comes back after a crash or a reboot.

Run one copy per token. Two copies polling the same bot compete for the same messages. If the bot is down for a while, Telegram keeps undelivered updates for up to 24 hours and the bot catches up when it returns.

The other way to receive messages is a webhook: Telegram sends each update to your HTTPS address. Set it with setWebhook, on port 443, 80, 88 or 8443. Add a secret_token and check the X-Telegram-Bot-Api-Secret-Token header on every request. While a webhook is set, getUpdates doesn't work, and deleteWebhook switches back to polling.

What limits does Telegram set?#

Telegram Bot API, version 10.3, checked on 2026-11-01:

LimitValue
Text per message1 to 4,096 characters
Messages to one chatAvoid more than 1 per second; bursts end in 429 errors
Messages to one groupNo more than 20 per minute
Messages to many usersAbout 30 per second, unless you pay for faster broadcasts
Files the bot downloadsUp to 20 MB
Files the bot sendsUp to 50 MB
Undelivered updatesKept for up to 24 hours

The group limit matters most for an AI bot. A long answer sent in three parts counts as three messages.

How much does a Telegram AI bot cost?#

Telegram itself doesn't charge for normal bot messages. Its FAQ says that "by default, bots are able to message their users at no cost". It charges Telegram Stars only for paid broadcasts above the normal rate. So the costs are the server and the model's tokens.

Each question sends the system prompt, the chat's memory and the new message. In this example, a bot answers 3,000 questions a month, at about 1,000 tokens in and 250 tokens out each:

Example: what Claude Sonnet 5.5 costs

3M input tokens and 750K output tokens

Our price$4.0570% below the official price
Official price$13.50

Official price from the provider's page, checked October 19, 2026.

The price per token for the default model:

Claude Sonnet 5.5 price per 1M tokens
Input$0.60Official price: $2
Output$3Official price: $10

Official price from the provider's page, checked October 19, 2026.

To spend less, pick a smaller model from the models list and use a key for its provider, lower MAX_HISTORY or lower max_tokens. You can compare providers on the API page and the Claude API page, and plan prices on the pricing page.

Give the bot its own key with a spend limit, as in Key controls. When the key reaches the limit, requests fail with API_KEY_QUOTA_EXHAUSTED and the bot sends its apology, so it stops spending at the limit you set.

How do you keep the token and key safe?#

  • Keep both in environment variables. Never write them into the code or commit them to a repository.
  • Use a separate key for the bot, with a spend limit and, if the server has a fixed address, an IP allow-list. The details are in Key controls.
  • Keep ALLOWED_CHAT_IDS short unless the bot is meant to be public.
  • If the bot token leaks, generate a new one with /token in BotFather. If the API key leaks, disable it and create a new one.

FAQ#

Does Telegram charge for bot messages?#

Not for normal messages. Telegram charges Stars only for paid broadcasts above the normal rate, so you pay for the model's tokens and the server.

Can the bot use GPT or Gemini instead of Claude?#

Yes. Set BOT_MODEL to a model id from the models list and use a key for that model's provider. Each key covers one provider, so a GPT model with a Claude key returns MODEL_PLATFORM_NOT_ALLOWED.

Does the bot remember the conversation?#

It remembers the last 10 messages of each chat while it runs. /reset clears that, and so does a restart. To keep memory across restarts, save history in a file or a database.

Does it work in groups?#

Yes, once the group's chat id is in ALLOWED_CHAT_IDS. By default, privacy mode is on: in a group the bot sees commands meant for it and replies to its own messages, not every message. A bot added as an admin sees all messages. To change privacy mode, use /setprivacy in BotFather, then remove the bot from the group and add it again. In a group, all members share one memory.

What happens when my balance runs out?#

Requests fail with INSUFFICIENT_BALANCE, and the bot answers with its apology until you top up. It keeps running, so it answers again once the balance is back.

How do I pay for the API?#

You top up your 5abeer balance with any method in Payment methods, and the bot's API calls draw from that balance.

Is 5abeer part of Telegram, OpenAI, Anthropic or Google?#

No. 5abeer is an independent service, not affiliated with any of them.

Sources#

Checked on 2026-11-01:

Get started#

Create a Claude key, put it in KHABEER_API_KEY and start the bot.