---
description: Reference for verified Telegram Bot API ingress from @flue/telegram.
title: Telegram Channel API | Flue
image: https://flueframework.com/docs/og4.jpg
---

# Telegram Channel API

AI-generated, awaiting review [ View as Markdown](https://flueframework.com/docs/api/telegram-channel/index.md) 

Import from `@flue/telegram`.

## `createTelegramChannel()`

```
function createTelegramChannel<E extends Env = Env>(
  options: TelegramChannelOptions<E>,
): TelegramChannel<E>;
```

Creates one stateless `POST /webhook` route.

## `TelegramChannelOptions`

```
interface TelegramChannelOptions<E extends Env = Env> {
  secretToken: string;
  bodyLimit?: number;
  webhook(input: TelegramWebhookHandlerInput<E>): TelegramHandlerResult;
}
```

| Field       | Description                                                               |
| ----------- | ------------------------------------------------------------------------- |
| secretToken | The 1-256 character secret\_token configured through Telegram setWebhook. |
| bodyLimit   | Maximum request body. Default: 1 MiB.                                     |
| webhook     | Callback for one verified provider-native Telegram Update.                |

`secretToken` accepts only Telegram’s documented `A-Z`, `a-z`, `0-9`, `_`, and`-` characters. It is required by Flue even though Telegram makes the setting optional.

```
interface TelegramWebhookHandlerInput<E extends Env = Env> {
  c: Context<E>;
  update: Update;
}

type TelegramHandlerResult =
  | undefined
  | JsonValue
  | Response
  | Promise<undefined | JsonValue | Response>;
```

The callback receives the Hono `Context` as `c` and the verified update as`update`. Returning nothing produces an empty `200`. A JSON-compatible value becomes the webhook response body and may use Telegram’s webhook-reply method format. An ordinary Hono or Fetch `Response` passes through.

## `TelegramChannel`

```
interface TelegramChannel<E extends Env = Env> {
  readonly routes: readonly ChannelRoute<E>[];
  conversationKey(ref: TelegramConversationRef): string;
  parseConversationKey(id: string): TelegramConversationRef;
}
```

A file named `channels/telegram.ts` serves`POST /channels/telegram/webhook` relative to the `flue()` mount.

The channel does not persist or deduplicate `update_id` values. Conversation keys are canonical identifiers, not authorization capabilities.

## Updates

```
import type { Update } from '@flue/telegram';
```

The verified `update` is the provider-native Telegram Bot API `Update`, re-exported from the official, spec-generated[@grammyjs/types](https://github.com/grammyjs/types) package — the same shape grammY itself uses. `@flue/telegram` does not define a parallel normalized model: updates are forwarded with Telegram’s own field names, nesting, and discriminants.

At most one of an `Update`’s optional fields is present per delivery, so branch on those fields directly rather than on a `type` discriminant:

```
async webhook({ update }) {
  const incoming =
    update.message ?? update.channel_post ?? update.business_message;
  if (incoming) {
    // incoming is a native Message
  } else if (update.callback_query) {
    // update.callback_query is a native CallbackQuery
  }
}
```

`update.update_id` is Telegram’s native ordering and duplicate-detection key. The channel validates only the envelope (a JSON object with a non-negative`update_id`); the full update is not exhaustively schema-checked. Derive conversation identity from the native `Message` (see below).

## Identity

```
type TelegramConversationRef =
  | {
      type: 'chat';
      chatId: number;
      messageThreadId?: number;
      directMessagesTopicId?: number;
    }
  | {
      type: 'business-chat';
      businessConnectionId: string;
      chatId: number;
      messageThreadId?: number;
      directMessagesTopicId?: number;
    };
```

`conversationKey()` serializes a `TelegramConversationRef` you derive from a native `Message`: read `message.chat.id`, `message.business_connection_id`,`message.message_thread_id`, and `message.direct_messages_topic?.topic_id`.`parseConversationKey()` is the inverse and accepts only canonical keys.

Regular and business chats remain separate because Telegram permits their chat identifiers to overlap; supply `businessConnectionId` for the `business-chat`type. Forum threads and direct-message topics are distinct destinations and cannot both be set.

Some native updates carry no durable chat destination. A guest message’s`guest_query_id` is a short-lived `answerGuestQuery` capability, not identity, and an inline `callback_query` without a `message` exposes no accessible chat. Do not derive a conversation key from either, and do not place such capability values in model context, logs, durable session data, or conversation keys.

## Errors

* `InvalidTelegramConversationKeyError`
* `InvalidTelegramInputError`, with structured `field`

See [Telegram setup](https://flueframework.com/docs/ecosystem/channels/telegram/) for webhook and grammY composition.

## Docs Navigation

Current page: [Telegram Channel API](https://flueframework.com/docs/api/telegram-channel/)

### Sections

* [Guide](https://flueframework.com/docs/getting-started/quickstart/)
* [Reference](https://flueframework.com/docs/api/agent-api/)
* [CLI](https://flueframework.com/docs/cli/overview/)
* [SDK](https://flueframework.com/docs/sdk/overview/)
* [Ecosystem](https://flueframework.com/docs/ecosystem/)

### Runtime

* [ Configuration ](https://flueframework.com/docs/reference/configuration/)
* [ Errors Reference ](https://flueframework.com/docs/api/errors-reference/)
* [ Agent API ](https://flueframework.com/docs/api/agent-api/)
* [ Provider API ](https://flueframework.com/docs/api/provider-api/)
* [ Routing API ](https://flueframework.com/docs/api/routing-api/)
* [ GitHub Channel ](https://flueframework.com/docs/api/github-channel/)
* [ Stripe Channel ](https://flueframework.com/docs/api/stripe-channel/)
* [ Notion Channel ](https://flueframework.com/docs/api/notion-channel/)
* [ Resend Channel ](https://flueframework.com/docs/api/resend-channel/)
* [ Shopify Channel ](https://flueframework.com/docs/api/shopify-channel/)
* [ Intercom Channel ](https://flueframework.com/docs/api/intercom-channel/)
* [ Zendesk Channel ](https://flueframework.com/docs/api/zendesk-channel/)
* [ Salesforce Marketing Cloud Channel ](https://flueframework.com/docs/api/salesforce-marketing-cloud-channel/)
* [ Slack Channel ](https://flueframework.com/docs/api/slack-channel/)
* [ Discord Channel ](https://flueframework.com/docs/api/discord-channel/)
* [ Teams Channel ](https://flueframework.com/docs/api/teams-channel/)
* [ Google Chat Channel ](https://flueframework.com/docs/api/google-chat-channel/)
* [ Linear Channel ](https://flueframework.com/docs/api/linear-channel/)
* [ Telegram Channel ](https://flueframework.com/docs/api/telegram-channel/)
* [ WhatsApp Channel ](https://flueframework.com/docs/api/whatsapp-channel/)
* [ Twilio Channel ](https://flueframework.com/docs/api/twilio-channel/)
* [ Messenger Channel ](https://flueframework.com/docs/api/messenger-channel/)
* [ Streaming Protocol ](https://flueframework.com/docs/api/streaming-protocol/)
* [ Events Reference ](https://flueframework.com/docs/api/events-reference/)

### Advanced

* [ Sandbox Adapter API ](https://flueframework.com/docs/api/sandbox-api/)
* [ Data Persistence API ](https://flueframework.com/docs/api/data-persistence-api/)