This workflow corresponds to n8n.io template #7664 — we link there as the canonical source.
This workflow follows the HTTP Request → Telegram Trigger recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "c995b5f4-c859-4ced-b5c3-2697043c714f",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
848,
2752
],
"parameters": {
"color": 5,
"width": 373,
"height": 602,
"content": "## \ud83c\udfaf Dynamic Menu Builder\n\n**This node processes incoming messages and builds dynamic menus**\n\n### Features:\n- \u2705 **Extracts real user names** from Telegram (first_name + last_name)\n- \ud83c\udfa8 **Creates dynamic keyboards** based on user actions\n- \u2b50 **Rating system** with 1-5 star buttons\n- \ud83d\udcca **Multiple menu levels** (Settings, Stats, Feedback)\n\n### How to customize:\n1. **Add new menu items**: Add cases in the switch statement\n2. **Change buttons**: Modify the `keyboard` arrays\n3. **Update messages**: Edit `responseText` strings\n4. **Add features**: Create new callback_data handlers\n\n### Callback Data Format:\n- `feature1` \u2192 Opens Feature 1\n- `rate_1` to `rate_5` \u2192 Rating buttons\n- `main` \u2192 Returns to main menu"
},
"typeVersion": 1
},
{
"id": "e240d222-5b4f-4f43-b2fc-5a71ee6ee69c",
"name": "Sticky Note ",
"type": "n8n-nodes-base.stickyNote",
"position": [
1232,
2752
],
"parameters": {
"color": 6,
"width": 320,
"height": 600,
"content": "## \ud83d\udd11 Bot Token Configuration\n\n**IMPORTANT: Replace with your bot token!**\n\n### Current token in SET node:\n`[ADD YOU BOT TOKET IN SET NODE]`\n\n### How to get your token:\n1. Open Telegram\n2. Search for @BotFather\n3. Send `/newbot` or use existing bot\n4. Copy the token\n5. Replace in SET node\n\n\u26a0\ufe0f **Security Note**: Never share your bot token publicly!"
},
"typeVersion": 1
},
{
"id": "7bf4da5a-d39f-4bd9-9a13-57cf9ab79188",
"name": "Sticky Note 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1568,
2752
],
"parameters": {
"color": 4,
"width": 280,
"height": 604,
"content": "## \ud83d\udea6 Message Router\n\n**Checks if incoming data is:**\n- \u2705 **TRUE**: Callback query (button click)\n- \u274c **FALSE**: Regular message\n\n### TRUE Branch:\n- Edits existing message\n- Answers callback to remove loading\n\n### FALSE Branch:\n- Sends new message with keyboard"
},
"typeVersion": 1
},
{
"id": "d8adb59a-0825-4c06-9e0f-867d8cd8f45c",
"name": "Sticky Note 7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1872,
2752
],
"parameters": {
"width": 300,
"height": 312,
"content": "## \ud83d\udce1 Telegram API Sender\n\n**Sends messages with inline keyboards**\n\n### API Methods:\n- `sendMessage` - New messages\n- `editMessageText` - Update existing\n\n### Why HTTP Request?\nn8n's Telegram node doesn't support dynamic inline keyboards, so we use direct API calls."
},
"typeVersion": 1
},
{
"id": "00ee79ff-145f-45e2-8304-08ce4675f4a6",
"name": "Sticky Note 8",
"type": "n8n-nodes-base.stickyNote",
"position": [
1904,
3312
],
"parameters": {
"color": 3,
"width": 276,
"height": 244,
"content": "## \u2705 Callback Answer\n\n**Removes the loading animation**\n\nWhen user clicks a button, Telegram shows loading until we answer the callback.\n\nThis node sends a simple \u2705 to acknowledge the click."
},
"typeVersion": 1
},
{
"id": "8d17f857-fd3a-4125-8c9a-cd5ce01d4311",
"name": "Sticky Note Main1",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
2656
],
"parameters": {
"color": 7,
"width": 1744,
"height": 1064,
"content": "# \ud83e\udd16 Telegram Bot Inline Keyboard with Dynamic Menus & Rating System\n\n## Quick Start:\n1. **Replace bot token** in Set Bot Token node\n2. **Set your telegram Credentials** in TG trigger node\n3. **Activate workflow** (toggle ON)\n4. **Message your bot** to see the menu\n\n## Features:\n- \ud83c\udfaf **Feature Rating**: 1-5 star rating system\n- \ud83d\udc64 **Personalized**: Uses real user names\n- \ud83d\udcf1 **Interactive Menus**: Multi-level navigation\n- \ud83d\udcac **Feedback System**: Collect user feedback\n\n## Common Issues:\n- **No keyboard?** Check bot token is correct\n- **Loading forever?** Answer Callback node must run\n- **Can't click buttons?** Ensure workflow is active"
},
"typeVersion": 1
},
{
"id": "bcbc464a-ddff-4168-b42d-19a3f958aabf",
"name": "TG Trigger node",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
608,
3488
],
"parameters": {
"updates": [
"message",
"callback_query"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "b172ee06-41dd-4fe4-8453-c841786e57c8",
"name": "Prepare Magic Response",
"type": "n8n-nodes-base.function",
"position": [
992,
3488
],
"parameters": {
"functionCode": "// Build dynamic keyboard based on message type\nconst data = items[0].json;\n\n// Prepare base response data\nlet chatId, messageId, userName, responseText, keyboard, isCallback = false;\nlet apiMethod = 'sendMessage';\n\nif (data.message) {\n // Handle regular message\n const message = data.message;\n chatId = message.chat.id;\n \n // Extract user's actual name from Telegram data\n const firstName = message.from.first_name || '';\n const lastName = message.from.last_name || '';\n userName = firstName;\n if (lastName) {\n userName += ` ${lastName}`;\n }\n if (!userName) {\n userName = 'User';\n }\n \n const text = (message.text || '').toLowerCase();\n \n // Determine response based on message\n if (text.includes('help')) {\n responseText = '\ud83d\udcda <b>Help Menu</b>\\n\\nAvailable commands:\\n\u2022 /start - Main menu\\n\u2022 /help - This help\\n\u2022 /rate - Rate features\\n\\nUse the buttons below!';\n keyboard = [\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n } else if (text.includes('settings')) {\n responseText = '\u2699\ufe0f <b>Settings Menu</b>\\n\\nConfigure your preferences:';\n keyboard = [\n [{ text: '\ud83d\udd14 Notifications', callback_data: 'notif' }],\n [{ text: '\ud83c\udf0d Language', callback_data: 'lang' }],\n [{ text: '\ud83d\udc64 Profile', callback_data: 'profile' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n } else {\n // Default main menu\n responseText = `Welcome ${userName}! \ud83d\udc4b\\n\\nI'm your assistant bot. Please select an option:`;\n keyboard = [\n [\n { text: '\ud83c\udfaf Feature 1', callback_data: 'feature1' },\n { text: '\ud83d\ude80 Feature 2', callback_data: 'feature2' }\n ],\n [\n { text: '\u2699\ufe0f Settings', callback_data: 'settings' },\n { text: '\u2753 Help', callback_data: 'help' }\n ],\n [\n { text: '\ud83d\udcca Statistics', callback_data: 'stats' },\n { text: '\ud83d\udcac Feedback', callback_data: 'feedback' }\n ]\n ];\n }\n \n} else if (data.callback_query) {\n // Handle callback query\n const callback = data.callback_query;\n chatId = callback.message.chat.id;\n messageId = callback.message.message_id;\n \n // Extract user's actual name from callback query\n const firstName = callback.from.first_name || '';\n const lastName = callback.from.last_name || '';\n userName = firstName;\n if (lastName) {\n userName += ` ${lastName}`;\n }\n if (!userName) {\n userName = 'User';\n }\n \n isCallback = true;\n apiMethod = 'editMessageText';\n \n const action = callback.data;\n \n switch(action) {\n case 'feature1':\n responseText = `\ud83c\udfaf <b>Feature 1 - Rating System Demo</b>\\n\\n${userName}, you've activated Feature 1!\\n\\nHow would you rate this feature?\\n\\nPlease select a rating from 1 to 5 stars:`;\n keyboard = [\n [\n { text: '\u2b50', callback_data: 'rate_1' },\n { text: '\u2b50\u2b50', callback_data: 'rate_2' },\n { text: '\u2b50\u2b50\u2b50', callback_data: 'rate_3' },\n { text: '\u2b50\u2b50\u2b50\u2b50', callback_data: 'rate_4' },\n { text: '\u2b50\u2b50\u2b50\u2b50\u2b50', callback_data: 'rate_5' }\n ],\n [\n { text: '\ud83d\udcad Skip Rating', callback_data: 'skip_rating' },\n { text: '\ud83d\udd19 Back to Main', callback_data: 'main' }\n ]\n ];\n break;\n \n case 'rate_1':\n responseText = `\ud83d\ude14 <b>Thank you for your feedback!</b>\\n\\n${userName}, you rated Feature 1: \u2b50 (1 star)\\n\\nWe're sorry to hear you didn't have a great experience. Your feedback helps us improve!\\n\\nWould you like to provide additional feedback?`;\n keyboard = [\n [{ text: '\ud83d\udcac Write Feedback', callback_data: 'write_feedback' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'rate_2':\n responseText = `\ud83d\ude10 <b>Thank you for your feedback!</b>\\n\\n${userName}, you rated Feature 1: \u2b50\u2b50 (2 stars)\\n\\nWe appreciate your honest feedback. We'll work on making this better!\\n\\nWould you like to tell us more?`;\n keyboard = [\n [{ text: '\ud83d\udcac Write Feedback', callback_data: 'write_feedback' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'rate_3':\n responseText = `\ud83d\ude42 <b>Thank you for your feedback!</b>\\n\\n${userName}, you rated Feature 1: \u2b50\u2b50\u2b50 (3 stars)\\n\\nGood to know! We're always looking to improve.\\n\\nAnything specific you'd like to share?`;\n keyboard = [\n [{ text: '\ud83d\udcac Share Thoughts', callback_data: 'write_feedback' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'rate_4':\n responseText = `\ud83d\ude0a <b>Thank you for your feedback!</b>\\n\\n${userName}, you rated Feature 1: \u2b50\u2b50\u2b50\u2b50 (4 stars)\\n\\nGreat! We're glad you enjoyed it!\\n\\nWhat could make it perfect?`;\n keyboard = [\n [{ text: '\ud83d\udca1 Suggest Improvement', callback_data: 'write_feedback' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'rate_5':\n responseText = `\ud83c\udf89 <b>Thank you for your feedback!</b>\\n\\n${userName}, you rated Feature 1: \u2b50\u2b50\u2b50\u2b50\u2b50 (5 stars)\\n\\nAmazing! We're thrilled you love it!\\n\\nWould you like to explore more features?`;\n keyboard = [\n [{ text: '\ud83d\ude80 Try Feature 2', callback_data: 'feature2' }],\n [{ text: '\ud83d\udcca View Statistics', callback_data: 'stats' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'skip_rating':\n responseText = `No problem, ${userName}! You can rate features anytime.\\n\\nWhat would you like to do next?`;\n keyboard = [\n [\n { text: '\ud83d\ude80 Try Feature 2', callback_data: 'feature2' },\n { text: '\ud83d\udcca Statistics', callback_data: 'stats' }\n ],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'write_feedback':\n responseText = `\ud83d\udcac <b>Feedback Form</b>\\n\\n${userName}, please type your feedback message and send it as a regular message.\\n\\nOr choose an option below:`;\n keyboard = [\n [{ text: '\ud83d\udc1b Report Bug', callback_data: 'bug_report' }],\n [{ text: '\ud83d\udca1 Suggest Feature', callback_data: 'feature_request' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'feature2':\n responseText = `\ud83d\ude80 <b>Feature 2 - Advanced Options</b>\\n\\n${userName}, welcome to Feature 2!\\n\\nThis feature includes:\\n\u2022 Data Analytics\\n\u2022 Custom Reports\\n\u2022 Export Options\\n\\nWhat would you like to do?`;\n keyboard = [\n [{ text: '\ud83d\udcc8 View Analytics', callback_data: 'analytics' }],\n [{ text: '\ud83d\udcc4 Generate Report', callback_data: 'report' }],\n [{ text: '\u2b50 Rate This Feature', callback_data: 'rate_feature2' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'rate_feature2':\n responseText = `\ud83d\ude80 <b>Rate Feature 2</b>\\n\\n${userName}, how would you rate Feature 2?\\n\\nSelect your rating:`;\n keyboard = [\n [\n { text: '1\ufe0f\u20e3', callback_data: 'f2_rate_1' },\n { text: '2\ufe0f\u20e3', callback_data: 'f2_rate_2' },\n { text: '3\ufe0f\u20e3', callback_data: 'f2_rate_3' },\n { text: '4\ufe0f\u20e3', callback_data: 'f2_rate_4' },\n { text: '5\ufe0f\u20e3', callback_data: 'f2_rate_5' }\n ],\n [{ text: '\ud83d\udd19 Back', callback_data: 'feature2' }]\n ];\n break;\n \n case 'profile':\n responseText = `\ud83d\udc64 <b>User Profile</b>\\n\\nName: ${userName}\\nUser ID: ${callback.from.id}\\nLanguage: ${callback.from.language_code || 'Not set'}\\n\\nProfile Settings:`;\n keyboard = [\n [{ text: '\u270f\ufe0f Edit Name', callback_data: 'edit_name' }],\n [{ text: '\ud83c\udf0d Change Language', callback_data: 'lang' }],\n [{ text: '\ud83d\udd19 Back to Settings', callback_data: 'settings' }]\n ];\n break;\n \n case 'stats':\n responseText = `\ud83d\udcca <b>Your Statistics</b>\\n\\n${userName}, here are your usage stats:\\n\\n\u2022 Features Used: 2\\n\u2022 Ratings Given: 1\\n\u2022 Active Days: 3\\n\u2022 Total Actions: 15\\n\\nKeep exploring to unlock achievements!`;\n keyboard = [\n [{ text: '\ud83c\udfc6 View Achievements', callback_data: 'achievements' }],\n [{ text: '\ud83d\udcc8 Detailed Stats', callback_data: 'detailed_stats' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'feedback':\n responseText = `\ud83d\udcac <b>Feedback Center</b>\\n\\n${userName}, we value your input!\\n\\nHow can we help you today?`;\n keyboard = [\n [{ text: '\u2b50 Rate Features', callback_data: 'rate_all' }],\n [{ text: '\ud83d\udca1 Suggest Ideas', callback_data: 'feature_request' }],\n [{ text: '\ud83d\udc1b Report Issues', callback_data: 'bug_report' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'help':\n responseText = `\ud83d\udcda <b>Help Menu</b>\\n\\n${userName}, here's how to use this bot:\\n\\n\u2022 Click buttons to navigate\\n\u2022 Rate features with 1-5 stars\\n\u2022 Submit feedback anytime\\n\u2022 Check your stats regularly\\n\\nNeed assistance?`;\n keyboard = [\n [{ text: '\ud83d\udcd6 User Guide', callback_data: 'guide' }],\n [{ text: '\u2753 FAQ', callback_data: 'faq' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'settings':\n responseText = `\u2699\ufe0f <b>Settings Menu</b>\\n\\n${userName}, configure your preferences:`;\n keyboard = [\n [{ text: '\ud83d\udd14 Notifications', callback_data: 'notif' }],\n [{ text: '\ud83c\udf0d Language', callback_data: 'lang' }],\n [{ text: '\ud83d\udc64 Profile', callback_data: 'profile' }],\n [{ text: '\ud83d\udd10 Privacy', callback_data: 'privacy' }],\n [{ text: '\ud83d\udd19 Back to Main', callback_data: 'main' }]\n ];\n break;\n \n case 'notif':\n responseText = '\ud83d\udd14 Notification settings updated successfully!';\n keyboard = [\n [{ text: '\ud83d\udd19 Back to Settings', callback_data: 'settings' }]\n ];\n break;\n \n case 'lang':\n responseText = '\ud83c\udf0d Select your preferred language:';\n keyboard = [\n [{ text: '\ud83c\uddec\ud83c\udde7 English', callback_data: 'lang_en' }],\n [{ text: '\ud83c\uddea\ud83c\uddf8 Espa\u00f1ol', callback_data: 'lang_es' }],\n [{ text: '\ud83c\uddeb\ud83c\uddf7 Fran\u00e7ais', callback_data: 'lang_fr' }],\n [{ text: '\ud83d\udd19 Back to Settings', callback_data: 'settings' }]\n ];\n break;\n \n case 'main':\n default:\n responseText = `Welcome back ${userName}! \ud83d\udc4b\\n\\nWhat would you like to do?`;\n keyboard = [\n [\n { text: '\ud83c\udfaf Feature 1', callback_data: 'feature1' },\n { text: '\ud83d\ude80 Feature 2', callback_data: 'feature2' }\n ],\n [\n { text: '\u2699\ufe0f Settings', callback_data: 'settings' },\n { text: '\u2753 Help', callback_data: 'help' }\n ],\n [\n { text: '\ud83d\udcca Statistics', callback_data: 'stats' },\n { text: '\ud83d\udcac Feedback', callback_data: 'feedback' }\n ]\n ];\n break;\n }\n}\n\n// Build the request body based on message type\nlet requestBody;\nif (isCallback) {\n requestBody = {\n chat_id: chatId,\n message_id: messageId,\n text: responseText,\n parse_mode: 'HTML',\n reply_markup: {\n inline_keyboard: keyboard\n }\n };\n} else {\n requestBody = {\n chat_id: chatId,\n text: responseText,\n parse_mode: 'HTML',\n reply_markup: {\n inline_keyboard: keyboard\n }\n };\n}\n\n// Return data for HTTP Request node\nreturn [{\n json: {\n apiMethod: apiMethod,\n requestBody: requestBody,\n isCallback: isCallback,\n callbackQueryId: data.callback_query ? data.callback_query.id : null\n }\n}];"
},
"typeVersion": 1
},
{
"id": "fa65924c-ea1b-447a-a8f0-16f73902882e",
"name": "Set Bot Token API KEY",
"type": "n8n-nodes-base.set",
"position": [
1296,
3488
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "bot-token",
"name": "botToken",
"type": "string",
"value": "PLACE YOUR TELEGRAM API KEY HERE "
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "a3eeae5e-1ae9-46c8-b881-7dc38200560b",
"name": "Is CALLBACK?",
"type": "n8n-nodes-base.if",
"position": [
1696,
3488
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.isCallback }}",
"value2": true
}
]
}
},
"typeVersion": 1
},
{
"id": "0db5584d-9ad1-46af-bff7-bca3bf305f16",
"name": "Send to Telegram API",
"type": "n8n-nodes-base.httpRequest",
"position": [
1968,
3120
],
"parameters": {
"url": "=https://api.telegram.org/bot{{ $json.botToken }}/{{ $json.apiMethod }}",
"method": "POST",
"options": {},
"jsonBody": "={{ JSON.stringify($json.requestBody) }}",
"sendBody": true,
"specifyBody": "json"
},
"typeVersion": 4.2
},
{
"id": "2aa00c9c-a450-42b5-bc39-96a5fda4bc21",
"name": "Answer Callback",
"type": "n8n-nodes-base.httpRequest",
"position": [
1968,
3568
],
"parameters": {
"url": "=https://api.telegram.org/bot{{ $('Set Bot Token API KEY').item.json.botToken }}/answerCallbackQuery",
"method": "POST",
"options": {},
"jsonBody": "={\n \"callback_query_id\": \"{{ $('Prepare Magic Response').item.json.callbackQueryId }}\",\n \"text\": \"\u2705\"\n}",
"sendBody": true,
"specifyBody": "json"
},
"typeVersion": 4.2
}
],
"connections": {
"Is CALLBACK?": {
"main": [
[
{
"node": "Send to Telegram API",
"type": "main",
"index": 0
},
{
"node": "Answer Callback",
"type": "main",
"index": 0
}
],
[
{
"node": "Send to Telegram API",
"type": "main",
"index": 0
}
]
]
},
"TG Trigger node": {
"main": [
[
{
"node": "Prepare Magic Response",
"type": "main",
"index": 0
}
]
]
},
"Set Bot Token API KEY": {
"main": [
[
{
"node": "Is CALLBACK?",
"type": "main",
"index": 0
}
]
]
},
"Prepare Magic Response": {
"main": [
[
{
"node": "Set Bot Token API KEY",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
telegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
🤖 Telegram Bot with Dynamic Menus & Rating System
Source: https://n8n.io/workflows/7664/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Try on any outfit virtually - right inside Telegram. A user sends a person photo, then a garment photo (captioned ), and the bot replies with an AI-generated try-on result image using a dedicated Virt
A robust n8n workflow designed to enhance Telegram bot functionality for user management and broadcasting. It facilitates automatic support ticket creation, efficient user data storage in Redis, and a
Transform your digital payment business with a fully-featured Telegram bot that handles everything from product listings to transaction processing. Perfect for entrepreneurs looking to automate their
TGBot. Uses telegram, googleSheets, telegramTrigger, httpRequest. Event-driven trigger; 30 nodes.
This template provides a workflow to integrate a Telegram bot with NeurochainAI's inference capabilities, supporting both text processing and image generation. Follow these steps to get started: