Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hunvreus/heypi/llms.txt

Use this file to discover all available pages before exploring further.

Heypi connects to Telegram using long polling — no public URL or webhook registration required. The adapter calls getUpdates in a continuous loop, processes each update, and automatically backs off if Telegram returns errors. This approach works out of the box for both local development and production deployments without any infrastructure changes.

Create a Bot

1

Open BotFather

In Telegram, start a conversation with @BotFather.
2

Create a new bot

Send the /newbot command. BotFather will ask for a display name and then a username ending in bot.
3

Copy the bot token

BotFather will reply with your bot token. Save it as an environment variable:
TELEGRAM_BOT_TOKEN=123456789:AAF...

Discover Chat IDs

Telegram bots cannot enumerate chats — the bot must observe an inbound message first. The telegram observe command temporarily takes over long polling for your token and prints IDs as messages arrive.
pnpm exec heypi telegram observe --env .env
Then send /start to the bot in a DM, or post a message in the target group or channel. The CLI prints a ready-to-paste snippet:
targets: { telegram: { channels: ["123456789"] } }
Use the printed chat ID in allow.chats (for groups and channels) or in scheduled job targets. For DM-only bots, leave allow.chats empty and restrict by user ID with allow.users instead.
telegram observe deletes any active webhook registered for the bot token before it starts polling. If another service is using the same token with a webhook, stop it first.

Configure the Adapter

import { createHeypi, runHeypi, telegram } from "@hunvreus/heypi";

const app = createHeypi({
  state: { root: "./state" },
  adapters: [
    telegram({
      token: process.env.TELEGRAM_BOT_TOKEN!,
      allow: {
        chats: ["-1001234567890"],  // Group/channel IDs
        users: ["8734062810"],      // Restrict to specific user IDs
        dms: true,                  // Allow direct messages
      },
      trigger: "mention",           // Only respond when @botusername is mentioned
      threadTrigger: "message",     // Respond to any message in forum topics
      streaming: true,
    }),
  ],
  // agent: ...
});

await runHeypi(app);

Config Reference

The allow object controls which chats and users can trigger the bot. The trigger and threadTrigger options are top-level adapter config, not nested under allow:
OptionNested underTypeDescription
allow.chatsallowstring[]Group or channel chat IDs (not applied to DMs)
allow.usersallowstring[]User IDs allowed to interact with the bot
allow.dmsallowbooleanWhether to accept direct messages
triggertop-level"mention" | "message""mention" requires @botusername; "message" responds to all messages
threadTriggertop-level"mention" | "message" | falseOverride trigger for forum topic replies
Telegram decides which updates heypi receives through bot membership, privacy mode, and long-polling delivery. Heypi’s allow config only filters updates after Telegram delivers them.

Groups Setup

1

Add the bot to the group

Use the group settings to add the bot as a member, or share the bot link with a group admin.
2

Observe the group chat ID

Run heypi telegram observe and post a message in the group. The CLI will print the group’s chat ID (a large negative number, e.g. -1001234567890).
3

Handle privacy mode

By default, Telegram bots in groups only receive messages that are commands (/command) or direct mentions. If you need the bot to see all messages, either:
  • Set trigger: "mention" and always mention the bot.
  • Disable privacy mode in BotFather with /setprivacy → Disable — then the bot receives every group message.
Forum topics (supergroups with topics enabled) use message_thread_id to identify the topic. Heypi maps each topic as a separate conversation thread. Use threadTrigger: "message" to respond to any message within a topic without requiring a mention.

Full Example

The following is the complete examples/telegram-workout entry point — a personal fitness coach bot with long polling, streaming, and a daily check-in heartbeat job:
import { agentFrom, coreTools, createHeypi, runHeypi, telegram, tool, workspace } from "@hunvreus/heypi";
import { Type } from "@sinclair/typebox";

const app = createHeypi({
  state: { root: "./state" },
  adapters: [
    telegram({
      token: process.env.TELEGRAM_BOT_TOKEN!,
      allow: {
        chats: (process.env.HEYPI_TELEGRAM_CHATS ?? "").split(",").map((s) => s.trim()).filter(Boolean),
        users: (process.env.HEYPI_TELEGRAM_USERS ?? "").split(",").map((s) => s.trim()).filter(Boolean),
      },
      trigger: "mention",
      streaming: true,
    }),
  ],
  agent: agentFrom("./agent", {
    model: "openai/gpt-5-mini",
    tools: [...coreTools(), getProfile, saveProfile, logWorkout],
  }),
  jobs: [
    {
      id: "daily-workout-checkin",
      kind: "heartbeat",
      everyMs: 24 * 60 * 60 * 1000,
      idleMs: 8 * 60 * 60 * 1000,
      scope: { telegram: {} },
      prompt:
        "Use the daily-checkin skill. Review the saved profile and decide whether to check in today based on the plan, rest days, and recent context.",
    },
  ],
  runtime: { root: workspace("./workspace") },
});

await runHeypi(app);

CLI Commands

heypi telegram check

Validates TELEGRAM_BOT_TOKEN and prints the bot’s identity (username, ID).
pnpm exec heypi telegram check --env .env

heypi telegram observe

Polls for inbound messages and prints chat and user IDs as they arrive. Send /start or post in a group to capture IDs.
pnpm exec heypi telegram observe --env .env

Common Failures

The bot token is invalid or has been revoked. Verify TELEGRAM_BOT_TOKEN is correct and that the bot has not been deleted in BotFather. Regenerate the token with /revoke in BotFather if needed.
One of the following:
  • The bot has a webhook registered somewhere else. Run telegram observe — it deletes the webhook automatically — but if another live service immediately re-registers it, stop that service first.
  • The message was sent before observe started polling. Send a new message after the CLI is running.
  • Group privacy mode blocked the message. Disable privacy mode in BotFather (/setprivacy → Disable) or send a direct command/mention.
Only one process can long-poll a bot token at a time. Stop any other running instances (including telegram observe) before starting your agent.
Confirm allow.chats includes the group’s chat ID (a large negative number). If trigger is "mention", the message must include @yourbotusername. If privacy mode is on, the bot only receives commands and mentions.

Build docs developers (and LLMs) love