Telegram Chat Surface Adapter
Chat surface adapters connect external chat products to the Agent plugin. They only receive and send chat messages. User linking is handled through OAuth connected accounts.
For Telegram you need both adapters:
pnpm i @adminforth/chat-surface-adapter-telegram
pnpm i @adminforth/oauth-adapter-telegram
Create a Telegram bot with BotFather and copy the token:
- Open BotFather.
- Click Open and open it in the Telegram app.
- Select or Create your bot.
- Copy the bot token shown at the top.
Add the token to .env:
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_BOT_USERNAME=your_bot_username_without_at
TELEGRAM_WEBHOOK_SECRET=your_random_secret
The webhook secret confirms that the request came through Telegram.
External identity externalUserId
External chat accounts are resolved through OAuth connected accounts. The Telegram OAuth adapter writes the Telegram user id into externalUserId on the external identities resource. The Agent plugin then uses that field to map incoming Telegram messages to AdminForth users.
Add the field to your external identities resource:
{
name: 'externalUserId',
type: AdminForthDataTypes.STRING,
},
Also add the matching column to your database schema and run a migration. For example, with Prisma and PostgreSQL:
model AdminUserExternalIdentity {
// existing fields
externalUserId String?
}
Then create and apply the migration using your app's migration scripts:
pnpm makemigration --name add-external-identity-external-user-id
pnpm migrate:local
Configure the OAuth plugin with Telegram OAuth:
import OAuthPlugin from '@adminforth/oauth';
import TelegramOauthAdapter from '@adminforth/oauth-adapter-telegram';
new OAuthPlugin({
emailField: 'email',
externalIdentityResource: {
resourceId: 'admin_user_external_identities',
phoneField: 'phone',
fullNameField: 'fullName',
avatarUrlField: 'avatarUrl',
metaField: 'meta',
},
adapters: [
new TelegramOauthAdapter({
clientID: process.env.TELEGRAM_CLIENT_ID as string,
clientSecret: process.env.TELEGRAM_CLIENT_SECRET as string,
redirectUri: process.env.TELEGRAM_OAUTH_REDIRECT_URI as string,
scopes: ['openid', 'profile', 'phone'],
}),
],
});
Then register the Telegram chat surface adapter in the Agent plugin:
import AdminForthAgent from '@adminforth/agent';
import TelegramChatSurfaceAdapter from '@adminforth/chat-surface-adapter-telegram';
new AdminForthAgent({
modes: [
// your modes
],
sessionResource: {
// your session resource config
},
turnResource: {
// your turn resource config
},
chatSurfaceAdapters: [
new TelegramChatSurfaceAdapter({
botToken: process.env.TELEGRAM_BOT_TOKEN as string,
botUsername: process.env.TELEGRAM_BOT_USERNAME,
webhookSecret: process.env.TELEGRAM_WEBHOOK_SECRET,
}),
],
chatExternalIdentityResource: {
resourceId: 'admin_user_external_identities',
surfaces: {
telegram: {
provider: 'AdminForthAdapterTelegramOauth2',
},
},
},
});
External chat users are resolved through OAuth connected accounts. Configure OAuth externalIdentityResource and Agent chatExternalIdentityResource, then let users connect Telegram from Connected Accounts.
The provider value must match the Telegram OAuth adapter class name. Users must connect Telegram in Settings -> Connected Accounts before the Telegram bot can identify them.
Adapter options
All options for new TelegramChatSurfaceAdapter(options):
botToken(string, required) — Telegram bot token from BotFather.botUsername(string, optional) — bot username. OAuth connected accounts are used for user linking.webhookSecret(string, optional) — secret token configured in TelegramsetWebhook.streamingMode(draft|typing|off, optional) — streaming behavior for Telegram responses.- Default:
draft. - Note: Telegram drafts work only in private chats. In non-private chats the adapter automatically falls back from
drafttotyping.
- Default:
draftUpdateIntervalMs(number, optional) — throttle for draft preview updates.- Default:
650.
- Default:
The plugin exposes this webhook endpoint:
/adminapi/v1/agent/surface/telegram/webhook
Set it in Telegram:
curl -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/adminapi/v1/agent/surface/telegram/webhook",
"secret_token": "'"${TELEGRAM_WEBHOOK_SECRET}"'"
}'
Telegram does not provide a user time zone in message updates, so the adapter sends UTC as userTimeZone.