Channels
Telegram
Webhook or poll inbound. A BotFather token is always required — hosted does not mint a bot. Self-host needs no Caspian API key. Same handlers in both modes (/help, /send, /reply, buttons, stream, …).
Self-host webhook
export TELEGRAM_BOT_TOKEN='…'
export TELEGRAM_WEBHOOK_URL='https://…' # ngrok / cloudflared (Python registers it)
export TELEGRAM_WEBHOOK_SECRET='…' # optional
export PORT=8080bot.py
cx = Caspian() # no Caspian key
cx.channels.add(
"telegram",
via="self-host",
bot_token=token,
webhook_url=webhook_url,
webhook_secret=webhook_secret,
)
# POST → cx.handle("telegram", body, headers)
# no public URL: cx.poll("telegram") — deleteWebhook firstbot.ts
const cx = new Caspian()
await cx.channels.add("telegram", {
via: "self-host",
bot_token: token,
webhook_secret, // optional
})
// POST → await cx.handle("telegram", body, headers)
// TypeScript add() does not setWebhook yet — register the URL after start.
// no public URL: await cx.poll("telegram")Hosted
export TELEGRAM_BOT_TOKEN='…'
export CASPIAN_API_KEY='…'cx = Caspian(api_key=api_key)
cx.channels.add("telegram", via="hosted", bot_token=token)
cx.run() # GET /v1/events → handle("gateway", …)const cx = new Caspian()
await cx.channels.add("telegram", { via: "hosted", bot_token: token })
await cx.run({ apiKey }) // GET /v1/events → handle("gateway", …)What it can do
Receive, reply, send, media, buttons, edit, delete, react, typing, pin, forward, threading, membership. send_blocks has no native Telegram blocks — it renders as text + keyboard.
Handlers in the example
Specific commands first, echo last. /reply calls thread.reply(msg.message_id, …) (quote). /send calls thread.send(…) (standalone, not a reply). Everything else uses thread.post. Buttons use on_action. Pin is groups/channels only.