@hitheo/telegram package connects Theo to Telegram as a bot. Users message your bot, Theo handles the response with the full orchestration pipeline, and the adapter replies through the Bot API.
Theo never hosts your bot. You create the bot with @BotFather, hold the token, and deploy this adapter on your infrastructure; Theo only processes the completion traffic the adapter forwards. That keeps every message, webhook URL, and credential under your control.
Prerequisites
- A Telegram bot token from @BotFather
- A Theo API key (
theo_sk_...)
Install
Quick Setup
createTelegramHandler returns an async function that processes a single Telegram webhook update. Wire it into any HTTP framework — Express, Next.js route handlers, Cloudflare Workers, AWS Lambda, etc.
How It Works
- User sends a message to your Telegram bot
- Telegram POSTs the update to your webhook URL
- The adapter verifies the
X-Telegram-Bot-Api-Secret-Tokenheader (whensecretTokenis configured) - The adapter forwards the text (and any photo/document attachments) to
POST /api/v1/completions, reusing theconversation_idassociated with that chat - Theo processes the request through the full pipeline (classification, skills, agent loop)
- The response is sent back to the Telegram chat, split into multiple messages if needed
Handler Config
Built-in Commands
The adapter handles three commands itself (no Theo call):
Any other
/foo command returns a short “Unknown command” reply.
Attachments
Photos attached to messages (and image documents) are downloaded inside the adapter and forwarded to Theo as base64 image data — the adapter never passes a Telegram file URL to Theo. This keeps the bot token inside your deployment. Voice and audio messages are ignored unless you setenableVoice: true. When enabled, the adapter downloads the voice clip, runs it through Theo speech-to-text, and appends the transcript to the prompt as text. Voice is not sent as an attachment — Theo’s completion endpoint only accepts image attachments.
Setting Up the Webhook
Register your webhook URL with Telegram and include thesecret_token:
Conversation Persistence Across Instances
The defaultConversationStore is an in-process Map — fine for a single long-running server, wrong for serverless (each invocation is a fresh process). Provide your own store:
Deploying
Deploy as any Node.js HTTP server. For production:- Railway / Render / Fly.io — easiest for webhook-based bots
- Vercel / Cloudflare Workers — serverless (one invocation per message); pair with a remote
conversationStore - Docker + PM2 — self-hosted
