Skip to content

Telegram

Overview#

The Telegram integration connects Cognest to the Telegram Bot API. It supports sending and receiving text, photo, and document messages, processing bot commands, handling inline keyboard callback queries, and editing or deleting messages. Cognest manages the webhook lifecycle automatically, registering and deregistering your endpoint on startup and shutdown.

Prerequisites#

  1. A Telegram bot created through @BotFather
  2. The bot token provided by BotFather after creating your bot
  3. A publicly accessible HTTPS endpoint for webhook delivery (or use cognest tunnel during development)

Bot Commands

Register your bot's commands with BotFather using /setcommands so users see autocomplete suggestions when they type /. Cognest will automatically route these commands to your registered handlers.

Configuration#

Add the Telegram integration to your cognest.config.yaml:

cognest.config.yaml
integrations:
  telegram:
    enabled: true
    credentials:
      bot_token: ${TELEGRAM_BOT_TOKEN}
    settings:
      webhook_path: "/webhooks/telegram"
      parse_mode: "HTML"
      disable_web_page_preview: false
      allowed_updates:
        - message
        - callback_query
        - edited_message

Store your bot token in an environment variable:

.env
# .env
TELEGRAM_BOT_TOKEN=7104583291:AAH2kf9sLm_pQxVb3nTzRwW8y5jK6dCeUoM

SDK Usage#

Register the integration programmatically if you prefer code-only configuration:

index.ts
import { Cognest } from '@cognest/sdk'
import { Telegram } from '@cognest/integrations/telegram'

const cognest = new Cognest({ configPath: false })

cognest.use(Telegram, {
  botToken: process.env.TELEGRAM_BOT_TOKEN!,
  settings: {
    webhookPath: '/webhooks/telegram',
    parseMode: 'HTML',
    disableWebPagePreview: false,
    allowedUpdates: ['message', 'callback_query', 'edited_message'],
  },
})

await cognest.start()

Available Methods#

Access Telegram methods through cognest.integration('telegram'):

MethodParametersDescription
`send(chatId, text, options?)``chatId`: number or string, `text`: message bodySend a text message to a chat, group, or channel
`sendPhoto(chatId, photo, options?)``chatId`: target chat, `photo`: URL, file_id, or BufferSend a photo with an optional caption
`sendDocument(chatId, document, options?)``chatId`: target chat, `document`: URL, file_id, or BufferSend a file as a document attachment
`editMessage(chatId, messageId, text, options?)``chatId`: target chat, `messageId`: message to editEdit the text of an existing message
`deleteMessage(chatId, messageId)``chatId`: target chat, `messageId`: message to deleteDelete a message from the chat (within 48 hours)
`answerCallback(callbackQueryId, options?)``callbackQueryId`: the callback query ID from the eventAcknowledge an inline keyboard callback query with an optional toast

Events#

Subscribe to events emitted by the Telegram integration:

EventPayloadDescription
`message``{ chatId, from, text, messageId, date }`Incoming text message from a user or group
`message:photo``{ chatId, from, photos, caption?, messageId }`Incoming photo message (photos array contains multiple sizes)
`message:document``{ chatId, from, document, caption?, messageId }`Incoming document or file attachment
`callback_query``{ callbackQueryId, chatId, from, data, messageId }`User pressed an inline keyboard button
`command``{ chatId, from, command, args, messageId }`Bot command received (e.g. /start, /help)

Example#

A complete Telegram bot that handles commands, messages, and inline keyboards:

bot.ts
import { Cognest } from '@cognest/sdk'
import { Telegram } from '@cognest/integrations/telegram'

const cognest = new Cognest()
const tg = cognest.integration<Telegram>('telegram')

// Handle /start command
cognest.on('telegram:command', async (ctx) => {
  const { chatId, command, args, from } = ctx.payload

  if (command === 'start') {
    await tg.send(chatId, `Welcome, ${from.firstName}! I'm your Cognest assistant.`, {
      replyMarkup: {
        inlineKeyboard: [
          [
            { text: 'Get Started', callbackData: 'onboard' },
            { text: 'View Help', callbackData: 'help' },
          ],
        ],
      },
    })
    return
  }

  if (command === 'status') {
    const uptime = process.uptime()
    await tg.send(chatId, `Bot uptime: ${Math.floor(uptime / 60)} minutes`)
    return
  }
})

// Handle text messages with AI
cognest.on('telegram:message', async (ctx) => {
  const { chatId, from, text, messageId } = ctx.payload

  // Ignore bot commands (handled above)
  if (text.startsWith('/')) return

  // Send typing indicator
  await tg.sendChatAction(chatId, 'typing')

  // Process with AI engine
  const response = await cognest.engine.chat({
    conversationId: `tg:${chatId}`,
    message: text,
    metadata: {
      channel: 'telegram',
      userId: String(from.id),
      username: from.username,
    },
  })

  await tg.send(chatId, response.text, {
    replyToMessageId: messageId,
  })
})

// Handle inline keyboard callbacks
cognest.on('telegram:callback_query', async (ctx) => {
  const { callbackQueryId, chatId, data, messageId } = ctx.payload

  // Acknowledge the callback immediately
  await tg.answerCallback(callbackQueryId)

  if (data === 'onboard') {
    await tg.editMessage(chatId, messageId, [
      'Great! Here is how to get started:',
      '',
      '1. Ask me any question',
      '2. Send a photo for analysis',
      '3. Use /status to check my health',
    ].join('\n'))
  }

  if (data === 'help') {
    await tg.send(chatId, 'Send me a message and I will respond using AI.')
  }
})

// Handle photo messages
cognest.on('telegram:message:photo', async (ctx) => {
  const { chatId, photos, caption } = ctx.payload

  // Use the highest resolution photo (last in the array)
  const bestPhoto = photos[photos.length - 1]
  const fileBuffer = await tg.downloadFile(bestPhoto.fileId)

  const analysis = await cognest.engine.vision({
    image: fileBuffer,
    prompt: caption || 'Describe this image.',
  })

  await tg.send(chatId, analysis.text)
})

await cognest.start()
console.log('Telegram bot is running')

Troubleshooting#

Common Issues

Webhook not receiving updates: Telegram requires a valid SSL certificate. Self-signed certificates are supported but must be uploaded via the setWebhook API. Use cognest tunnel for local development. 409 Conflict errors: Another process is polling or has a webhook registered for the same bot token. Only one webhook can be active at a time. Call the deleteWebhook API first or stop any other bot instances. Messages not editing: You can only edit messages sent by the bot, and only within 48 hours. Attempting to edit another user's message will fail silently. Callback queries timing out: You must call answerCallback() within 30 seconds of receiving the callback_query event, or Telegram will show a loading spinner to the user.