Setup

Create a Telegram bot with BotFather and configure webhooks for local and production deployments.

Install the Telegram and example model dependencies: uv pip install 'agno[os,telegram]' openai

Local Development

Prerequisites

Ensure you have the following:

  • A Telegram account
  • ngrok (for development)
  • Python 3.9+

Create a Telegram Bot

  1. Open Telegram and message @BotFather
  2. Send /newbot and follow the prompts to choose a display name and username (username must end in bot, e.g. my_agno_bot)
  3. Copy the bot token (looks like 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)

Set Environment Variables

export TELEGRAM_TOKEN="your-bot-token-from-botfather"
export TELEGRAM_WEBHOOK_SECRET_TOKEN="your-random-webhook-secret"
export OPENAI_API_KEY="your_openai_api_key"
unset APP_ENV  # Keep webhook verification enabled for the public tunnel

Start a Tunnel with ngrok

Telegram needs a public HTTPS URL to deliver webhook events:

ngrok http 7777

Copy the https:// forwarding URL provided by ngrok and set it as an environment variable:

export NGROK_URL=https://your-subdomain.ngrok-free.app

Run the App

Save the following as telegram_bot.py:

from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS
from agno.os.interfaces.telegram import Telegram

agent = Agent(
    id="telegram-assistant",
    model=OpenAIResponses(id="gpt-5.4"),
    db=SqliteDb(db_file="tmp/telegram.db"),
    add_history_to_context=True,
)
agent_os = AgentOS(agents=[agent], interfaces=[Telegram(agent=agent)])
app = agent_os.get_app()

if __name__ == "__main__":
    agent_os.serve(app="telegram_bot:app", port=7777)

See the current session lookup limitation when serving multiple chats from persistent storage.

python telegram_bot.py

The server starts on http://localhost:7777.

Register the Webhook

Tell Telegram to send updates to your tunnel URL:

curl -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/setWebhook" \
  --data-urlencode "url=${NGROK_URL}/telegram/webhook" \
  --data-urlencode "secret_token=${TELEGRAM_WEBHOOK_SECRET_TOKEN}"

You should see {"ok":true,"result":true,"description":"Webhook was set"}.

Verify anytime with:

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

Production Deployment

Keep webhook secret validation enabled for public tunnels and production alike. Use a Telegram-compatible secret: 1–256 letters, digits, underscores, or hyphens. Telegram sends the secret in the X-Telegram-Bot-Api-Secret-Token header, and the interface rejects requests with an invalid or missing token with a 403.

Set the Webhook Secret

Generate a secret and set it as an environment variable:

export TELEGRAM_WEBHOOK_SECRET_TOKEN="your-random-secret-string"

Register the Webhook with the Secret

Pass the secret_token parameter when registering your webhook:

curl "https://api.telegram.org/bot${TELEGRAM_TOKEN}/setWebhook?url=https://your-domain.com/telegram/webhook&secret_token=${TELEGRAM_WEBHOOK_SECRET_TOKEN}"

Remove APP_ENV=development

Reserve APP_ENV=development for isolated payload tests that cannot receive network traffic. Do not use it for a public tunnel or production. Without it, webhook secret validation is active.

ngrok is for local development only. For production, see the deployment templates.