Skip to main content

Telegram

Source: https://docs.datzi.ai/channels/telegram

Telegram (Bot API)

Status: production-ready for bot DMs + groups via grammY. Long polling is the default mode; webhook mode is optional.

Quick setup

1

Create the bot token in BotFather

Open Telegram and chat with @BotFather (confirm the handle is exactly @BotFather).Run /newbot, follow prompts, and save the token.
2

Configure token and DM policy

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123:abc",
      dmPolicy: "pairing",
      groups: { "*": { requireMention: true } },
    },
  },
}
Env fallback: TELEGRAM_BOT_TOKEN=... (default account only).
3

Start gateway and approve first DM

datzi gateway
datzi pairing list telegram
datzi pairing approve telegram <CODE>
Pairing codes expire after 1 hour.
4

Add the bot to a group

Add the bot to your group, then set channels.telegram.groups and groupPolicy to match your access model.

Telegram side settings

Privacy mode and group visibility

Telegram bots default to Privacy Mode, which limits what group messages they receive. If the bot must see all group messages, either:
  • disable privacy mode via /setprivacy, or
  • make the bot a group admin.
When toggling privacy mode, remove + re-add the bot in each group so Telegram applies the change.

Helpful BotFather toggles

  • /setjoingroups to allow/deny group adds
  • /setprivacy for group visibility behavior

Access control and activation

channels.telegram.dmPolicy controls direct message access:
  • pairing (default)
  • allowlist
  • open (requires allowFrom to include "*")
  • disabled
channels.telegram.allowFrom accepts numeric Telegram user IDs. telegram: / tg: prefixes are accepted and normalized.

Finding your Telegram user ID

Safer (no third-party bot):
  1. DM your bot.
  2. Run datzi logs --follow.
  3. Read from.id.
Official Bot API method:
curl "https://api.telegram.org/bot<bot_token>/getUpdates"

Group policy and allowlists

There are two independent controls:
  1. Which groups are allowed (channels.telegram.groups)
    • no groups config: all groups allowed
    • groups configured: acts as allowlist (explicit IDs or "*")
  2. Which senders are allowed in groups (channels.telegram.groupPolicy)
    • open
    • allowlist (default)
    • disabled
groupAllowFrom is used for group sender filtering. If not set, Telegram falls back to allowFrom. Example: allow any member in one specific group:
{
  channels: {
    telegram: {
      groups: {
        '-1001234567890': {
          groupPolicy: 'open',
          requireMention: false
        }
      }
    }
  }
}

Mention behavior

Group replies require mention by default. Mention can come from:
  • native @botusername mention, or
  • mention patterns in:
    • agents.list[].groupChat.mentionPatterns
    • messages.groupChat.mentionPatterns
Session-level command toggles:
  • /activation always
  • /activation mention
Persistent config example:
{
  channels: {
    telegram: {
      groups: {
        '*': { requireMention: false }
      }
    }
  }
}

Runtime behavior

  • Telegram is owned by the gateway process.
  • Routing is deterministic: Telegram inbound replies back to Telegram.
  • Group sessions are isolated by group ID. Forum topics append :topic:<threadId> to keep topics isolated.
  • Long polling uses grammY runner with per-chat/per-thread sequencing.

Feature reference

Live stream preview (message edits)

Datzi can stream partial replies by sending a temporary Telegram message and editing it as text arrives. channels.telegram.streaming is off | partial | block | progress (default: off)

Formatting and HTML fallback

Outbound text uses Telegram parse_mode: "HTML".
  • Markdown-ish text is rendered to Telegram-safe HTML.
  • Raw model HTML is escaped to reduce Telegram parse failures.
  • If Telegram rejects parsed HTML, Datzi retries as plain text.
Link previews are enabled by default and can be disabled with channels.telegram.linkPreview: false.

Native commands and custom commands

Telegram command menu registration is handled at startup with setMyCommands. commands.native: "auto" enables native commands for Telegram. Add custom command menu entries:
{
  channels: {
    telegram: {
      customCommands: [
        { command: 'backup', description: 'Git backup' },
        { command: 'generate', description: 'Create an image' }
      ]
    }
  }
}

Inline buttons

Configure inline keyboard scope:
{
  channels: {
    telegram: {
      capabilities: {
        inlineButtons: 'allowlist'
      }
    }
  }
}
Scopes:
  • off
  • dm
  • group
  • all
  • allowlist (default)
Message action example:
{
  action: 'send',
  channel: 'telegram',
  to: '123456789',
  message: 'Choose an option:',
  buttons: [
    [
      { text: 'Yes', callback_data: 'yes' },
      { text: 'No', callback_data: 'no' }
    ],
    [{ text: 'Cancel', callback_data: 'cancel' }]
  ]
}
Callback clicks are passed to the agent as text: callback_data: <value>

Forum topics and thread behavior

Forum supergroups:
  • topic session keys append :topic:<threadId>
  • replies and typing target the topic thread
  • topic config path: channels.telegram.groups.<chatId>.topics.<threadId>
General topic (threadId=1) special-case:
  • message sends omit message_thread_id (Telegram rejects sendMessage(...thread_id=1))
  • typing actions still include message_thread_id

Audio, video, and stickers

Telegram distinguishes voice notes vs audio files.
  • default: audio file behavior
  • tag [[audio_as_voice]] in agent reply to force voice-note send
Enable sticker actions:
{
  channels: {
    telegram: {
      actions: {
        sticker: true
      }
    }
  }
}
Send sticker action:
{
  action: 'sticker',
  channel: 'telegram',
  to: '123456789',
  fileId: 'CAACAgIAAxkBAAI...'
}
Search cached stickers:
{
  action: 'sticker-search',
  channel: 'telegram',
  query: 'cat waving',
  limit: 5
}

Reaction notifications

When enabled, Datzi enqueues system events like:
  • Telegram reaction added: 👍 by Alice (@alice) on msg 42
Config:
  • channels.telegram.reactionNotifications: off | own | all (default: own)
  • channels.telegram.reactionLevel: off | ack | minimal | extensive (default: minimal)

Long polling vs webhook

Default: long polling. Webhook mode:
  • set channels.telegram.webhookUrl
  • set channels.telegram.webhookSecret (required when webhook URL is set)
  • optional channels.telegram.webhookPath (default /telegram-webhook)
  • optional channels.telegram.webhookHost (default 127.0.0.1)
Default local listener for webhook mode binds to 127.0.0.1:8787.

Troubleshooting

  • Bot does not respond to non mention group messages: check privacy mode via BotFather (/setprivacy -> Disable) and remove + re-add bot.
  • Bot not seeing group messages at all: when channels.telegram.groups exists, group must be listed or include "*".
  • Commands work partially or not at all: authorize your sender identity; setMyCommands failed indicates DNS/HTTPS issues to api.telegram.org.
  • Polling or network instability: check IPv6 egress if Telegram API calls fail intermittently.

Telegram config reference pointers

  • channels.telegram.enabled: enable/disable channel startup.
  • channels.telegram.botToken: bot token (BotFather).
  • channels.telegram.dmPolicy: pairing | allowlist | open | disabled (default: pairing).
  • channels.telegram.allowFrom: DM allowlist (numeric Telegram user IDs).
  • channels.telegram.groupPolicy: open | allowlist | disabled (default: allowlist).
  • channels.telegram.groupAllowFrom: group sender allowlist (numeric Telegram user IDs).
  • channels.telegram.groups: per-group defaults + allowlist (use "*" for global defaults).
  • channels.telegram.capabilities.inlineButtons: off | dm | group | all | allowlist (default: allowlist).
  • channels.telegram.replyToMode: off | first | all (default: off).
  • channels.telegram.textChunkLimit: outbound chunk size (chars).
  • channels.telegram.streaming: off | partial | block | progress (live stream preview; default: off).
  • channels.telegram.mediaMaxMb: inbound/outbound media cap (MB).
  • channels.telegram.proxy: proxy URL for Bot API calls (SOCKS/HTTP).
  • channels.telegram.webhookUrl: enable webhook mode.