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.
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.
Add the Telegram integration to your 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_messageStore your bot token in an environment variable:
# .env
TELEGRAM_BOT_TOKEN=7104583291:AAH2kf9sLm_pQxVb3nTzRwW8y5jK6dCeUoMRegister the integration programmatically if you prefer code-only configuration:
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()Access Telegram methods through cognest.integration('telegram'):
| Method | Parameters | Description |
|---|---|---|
| `send(chatId, text, options?)` | `chatId`: number or string, `text`: message body | Send a text message to a chat, group, or channel |
| `sendPhoto(chatId, photo, options?)` | `chatId`: target chat, `photo`: URL, file_id, or Buffer | Send a photo with an optional caption |
| `sendDocument(chatId, document, options?)` | `chatId`: target chat, `document`: URL, file_id, or Buffer | Send a file as a document attachment |
| `editMessage(chatId, messageId, text, options?)` | `chatId`: target chat, `messageId`: message to edit | Edit the text of an existing message |
| `deleteMessage(chatId, messageId)` | `chatId`: target chat, `messageId`: message to delete | Delete a message from the chat (within 48 hours) |
| `answerCallback(callbackQueryId, options?)` | `callbackQueryId`: the callback query ID from the event | Acknowledge an inline keyboard callback query with an optional toast |
Subscribe to events emitted by the Telegram integration:
| Event | Payload | Description |
|---|---|---|
| `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) |
A complete Telegram bot that handles commands, messages, and inline keyboards:
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')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.