AutomationFlowsSlack & Telegram › Menu Handler

Menu Handler

Menu-Handler. Uses telegramTrigger, chatTrigger, executeWorkflowTrigger, chainLlm. Event-driven trigger; 28 nodes.

Event trigger★★★★☆ complexityAI-powered28 nodesTelegram TriggerChat TriggerExecute Workflow TriggerChain LlmGroq ChatOutput Parser StructuredMemory Postgres ChatHTTP Request
Slack & Telegram Trigger: Event Nodes: 28 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Chainllm → Chat 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 →

Download .json
{
  "nodes": [
    {
      "parameters": {
        "updates": [
          "callback_query",
          "message"
        ],
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.1,
      "position": [
        8720,
        3648
      ],
      "id": "756266fc-787c-4fe7-b908-2d153548989e",
      "name": "Telegram Trigger",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "typeVersion": 1.1,
      "position": [
        8720,
        3792
      ],
      "id": "dd0f0bb0-9a5c-4579-98ad-e7cfb4b53407",
      "name": "Chat Trigger"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        8720,
        3936
      ],
      "id": "ewt00001-0001-0001-0001-000000000001",
      "name": "Execute Workflow Trigger"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "whitelist-check",
              "leftValue": "={{ String($json.callback_query?.from?.id ?? $json.message?.from?.id ?? '') }}",
              "rightValue": "^(YOUR_CHAT_ID_1|YOUR_CHAT_ID_2)$",
              "operator": {
                "type": "string",
                "operation": "regex"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        8928,
        3664
      ],
      "id": "21fc2941-9541-40bd-934d-f05ded7688c4",
      "name": "Whitelist",
      "disabled": true
    },
    {
      "parameters": {
        "jsCode": "// Agent registry \u2014 add new agents here, update Classifier Output Parser enum to match\nconst agents = {\n  expenses: {\n    workflowId: 'jJmiXA2vJbkk3WKX', // YOUR_EXPENSE_REPORT_WORKFLOW_ID\n    label: 'Expense Report',\n    desc: 'Monthly expense trends and charts from billing ledger',\n    ready: true\n  },\n  learning: {\n    workflowId: 'IKA8U9z7bVwCYuhU', // YOUR_LEARNING_NOTES_WORKFLOW_ID\n    label: 'Learning Notes',\n    desc: 'AI-summarized notes from Notion knowledge base',\n    ready: true\n  },\n  deals: {\n    workflowId: '2_Jk_DnmQcnpRdceAsh21', // YOUR_DEAL_FINDER_WORKFLOW_ID\n    label: 'Deal Finder',\n    desc: 'Product deal-finder and price tracker. Tracks specific product URLs for daily price updates. Researches deals and alternatives from Swiss retailers.',\n    ready: true,\n    subCommands: [\n      'add <category> <price> <constraints>',\n      'track <url>',\n      'tracked',\n      'untrack <name>',\n      'check_prices',\n      'history <name>',\n      'plot'\n    ]\n  }\n};\n\n// Pass through trigger data + inject registry\nreturn [{ json: { ...$json, agents } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        9120,
        3720
      ],
      "id": "cfg00001-0001-0001-0001-000000000001",
      "name": "Config"
    },
    {
      "parameters": {
        "jsCode": "const agents = $json.agents;\nconst knownActions = Object.keys(agents).filter(k => agents[k].ready && agents[k].workflowId);\nconst builtinActions = ['help'];\n\nconst cb = $json.callback_query;\nconst msg = $json.message;\nconst chatInput = $json.chatInput;\n\nlet action = 'chat';\nlet chatId = '';\nlet text = '';\n\nif (chatInput) {\n  text = chatInput.trim();\n  chatId = 'n8n-chat';\n} else if (cb) {\n  const data = cb.data || '';\n  const extracted = data.includes(':') ? data.split(':')[1] : data;\n  chatId = String(cb.message?.chat?.id || '');\n\n  if (knownActions.includes(extracted) || builtinActions.includes(extracted)) {\n    action = extracted;\n  } else {\n    text = extracted;\n  }\n} else if (msg) {\n  chatId = String(msg.chat?.id || '');\n  const raw = (msg.text || '').trim();\n  if (raw.startsWith('/')) {\n    const parts = raw.substring(1).split(/\\s+/);\n    const cmd = parts[0].toLowerCase();\n    if (knownActions.includes(cmd) || builtinActions.includes(cmd)) {\n      action = cmd;\n    }\n    text = parts.slice(1).join(' ');\n  } else {\n    text = raw;\n  }\n} else if ($json.text) {\n  // Execute Workflow Trigger: text + chatId from parent workflow\n  text = ($json.text || '').trim();\n  chatId = $json.chatId || 'subworkflow';\n}\n\nconst workflowId = agents[action]?.workflowId || '';\nreturn [{ json: { action, chatId, text, workflowId, agents } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        9328,
        3720
      ],
      "id": "94110c9a-e70a-4a35-a1fa-055768533bb0",
      "name": "Normalize"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "route-help",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "help",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "help"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "route-agent",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "chat",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    }
                  },
                  {
                    "id": "route-agent-not-help",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "help",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "agent"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "route-chat",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "chat",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "chat"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        9536,
        3680
      ],
      "id": "5e349338-c82d-4cf6-a3a1-679dad5456c9",
      "name": "Route"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "={{ $json.workflowId }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.2,
      "onError": "continueOnFail",
      "position": [
        9760,
        3600
      ],
      "id": "a0e8c921-08ea-4f20-859b-3e1f6a2076b6",
      "name": "Run Skill"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=You are a routing agent. Analyze the user's input and conversation context, then route to the best handler.\n\nAvailable agents (use for domain-specific tasks):\n{{ Object.entries($json.agents).map(([k,v]) => '- ' + k + ': ' + v.desc + (v.ready ? '' : ' [coming soon \u2014 tell user this is not available yet]')).join('\\n') }}\n\nAvailable LLM backends (use for general queries):\n- groq_reasoning: AI reasoning, analysis, creative writing, coding, complex problem solving\n- brave_search: Simple factual lookups, \"what is\", \"who is\", basic search queries\n- perplexity: Research, comparisons, investigations, comprehensive studies\n\nUser Input: {{ $json.text }}\n\nRoute to the most specific handler. Prefer agents over LLM backends when the query clearly matches an agent's domain.",
        "hasOutputParser": true,
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        9760,
        3880
      ],
      "id": "de46fe69-de1e-41a7-b3c2-332c87038e99",
      "name": "AI Classifier"
    },
    {
      "parameters": {
        "model": "openai/gpt-oss-120b",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "typeVersion": 1,
      "position": [
        9760,
        4100
      ],
      "id": "bb5dc33a-944e-437a-878a-bfdf75fd2572",
      "name": "Groq Classifier LLM",
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"route_type\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"enum\": [\"expenses\", \"learning\", \"deals\", \"groq_reasoning\", \"brave_search\", \"perplexity\"],\n\t\t\t\"description\": \"Which handler should process this request\"\n\t\t},\n\t\t\"query\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"The original user query/input\"\n\t\t},\n\t\t\"reasoning\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Brief explanation of why this route was chosen\"\n\t\t}\n\t},\n\t\"required\": [\"route_type\", \"query\", \"reasoning\"]\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        9888,
        4100
      ],
      "id": "94b2eb32-3622-4fb6-a45d-80826290b229",
      "name": "Classifier Output Parser"
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Normalize').first().json.chatId }}",
        "contextWindowLength": 10
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        9632,
        4100
      ],
      "id": "mem00001-0001-0001-0001-000000000001",
      "name": "Router Memory",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 1
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.output.route_type }}",
                    "rightValue": "groq_reasoning",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "groq"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 1
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.output.route_type }}",
                    "rightValue": "brave_search",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "brave"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 1
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.output.route_type }}",
                    "rightValue": "perplexity",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "perplexity"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        10000,
        3880
      ],
      "id": "1cdc9c5d-7fa2-4d08-b8c0-2f2fd80e967f",
      "name": "LLM Route"
    },
    {
      "parameters": {
        "jsCode": "const agents = $('Config').first().json.agents;\nconst routeType = $json.output.route_type;\nconst agent = agents[routeType];\nconst chatId = $('Normalize').first().json.chatId;\nconst text = $('Normalize').first().json.text;\n\nif (!agent || !agent.ready || !agent.workflowId) {\n  return [{ json: {\n    response: `I don't have the ${agent?.label || routeType} capability yet.`,\n    chatId\n  }}];\n}\n\nreturn [{ json: { workflowId: agent.workflowId, chatId, text, action: routeType } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        10240,
        3640
      ],
      "id": "res00001-0001-0001-0001-000000000001",
      "name": "Resolve Agent"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "={{ $json.workflowId }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.2,
      "onError": "continueOnFail",
      "position": [
        10464,
        3640
      ],
      "id": "ewa00001-0001-0001-0001-000000000001",
      "name": "Run Skill (AI)"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $node['AI Classifier'].json.output.query }}",
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        10240,
        3800
      ],
      "id": "035f3fed-c25a-4a27-977c-700f8545101b",
      "name": "Groq Reasoning"
    },
    {
      "parameters": {
        "model": "meta-llama/llama-4-maverick-17b-128e-instruct",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "typeVersion": 1,
      "position": [
        10240,
        3980
      ],
      "id": "929c9914-1217-4860-b08c-8259cad0e44f",
      "name": "Groq Reasoning LLM",
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "https://api.search.brave.com/res/v1/web/search",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $node['AI Classifier'].json.output.query }}"
            },
            {
              "name": "count",
              "value": "5"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        10240,
        4080
      ],
      "id": "41b1dac7-daa6-4486-aabe-f9142943c3fe",
      "name": "Brave Search",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "messages": {
          "message": [
            {
              "content": "={{ $node['AI Classifier'].json.output.query }}"
            }
          ]
        },
        "options": {},
        "requestOptions": {}
      },
      "type": "n8n-nodes-base.perplexity",
      "typeVersion": 1,
      "position": [
        10240,
        4280
      ],
      "id": "daf3c0c5-8ffa-40d5-ab86-9516fe0b10a3",
      "name": "Perplexity Research"
    },
    {
      "parameters": {
        "jsCode": "// Format all LLM route responses into unified output\nconst data = $input.first().json;\nconst classifier = $node['AI Classifier'].json.output;\nconst chatId = $node['Normalize'].json.chatId;\n\nlet response = '';\n\n// Helper to strip HTML entities/tags from Brave API responses\nconst clean = (s) => s\n  .replace(/<[^>]+>/g, '')\n  .replace(/&amp;/g, '&')\n  .replace(/&quot;/g, '\"')\n  .replace(/&#x27;/g, \"'\")\n  .replace(/&lt;/g, '<')\n  .replace(/&gt;/g, '>')\n  .replace(/&nbsp;/g, ' ');\n\nif (data.web && data.web.results !== undefined) {\n  // Route 1: Brave Search\n  const results = data.web.results || [];\n  if (results.length > 0) {\n    const top = results.slice(0, 3);\n    response = top.map((item, i) => {\n      const desc = clean(item.description || '').slice(0, 80);\n      return `${i + 1}. [${clean(item.title)}](${item.url})\\n   ${desc}`;\n    }).join('\\n\\n');\n  } else {\n    response = 'No search results found.';\n  }\n} else if (data.choices && data.choices[0]) {\n  // Route 2: Perplexity\n  response = data.choices[0].message.content || 'No research results.';\n} else {\n  // Route 0: Groq Reasoning\n  response = data.text || data.response || 'No response generated.';\n}\n\nreturn [{ json: { response, chatId } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        10480,
        4080
      ],
      "id": "a3a5ce05-f339-423b-b35e-e11d37ee90d7",
      "name": "Format Response"
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.response }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        10704,
        4080
      ],
      "id": "85d63d7d-2691-4d12-a879-21c6783cd497",
      "name": "Send Reply",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Guard: only forward if subworkflow returned a response.\n// Subworkflows that send their own Telegram replies return no 'response' field.\nconst data = $input.first().json || {};\nconst chatId = data.chatId || $('Normalize').first().json.chatId;\n\n// continueOnFail error payload \u2014 reply with friendly message, don't cascade\nif (data.error) {\n  return [{ json: { chatId, response: 'Sorry, this feature is temporarily unavailable. Please try again later.' } }];\n}\n\nconst response = data.response || '';\n\nif (!response) {\n  // Subworkflow handled its own reply \u2014 nothing to forward\n  return [];\n}\n\nreturn [{ json: { chatId, response } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        10480,
        3600
      ],
      "id": "fsr00001-0001-0001-0001-000000000001",
      "name": "Format Skill Response"
    },
    {
      "parameters": {
        "jsCode": "// Generate dynamic help message from agents registry\nconst agents = $json.agents;\nconst chatId = $json.chatId;\n\nconst sections = [];\nfor (const [key, agent] of Object.entries(agents)) {\n  if (!agent.ready) continue;\n  sections.push(`  /${key} \u2014 ${agent.desc}`);\n  if (agent.subCommands) {\n    for (const sub of agent.subCommands) {\n      sections.push(`    /${key} ${sub}`);\n    }\n  }\n}\n\nconst response = `*Available commands:*\\n\\n${sections.join('\\n')}\\n\\n  /help \u2014 This message\\n\\nOr just send me a question in plain text.`;\nreturn [{ json: { chatId, response } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        9760,
        3480
      ],
      "id": "hlp00001-0001-0001-0001-000000000001",
      "name": "Build Help"
    },
    {
      "parameters": {
        "content": "## Menu Handler v2 \u2014 Config-Driven + Memory\n\nHub-and-spoke with intelligent routing.\n\n### Entry Points\n- Telegram Trigger (buttons + messages)\n- Chat Trigger (MCP/programmatic)\n- Execute Workflow Trigger (subworkflow calls)\n\n### 1. Agent Registry (Config node)\nAdd new agents by editing the Config node only. No other changes needed\nfor button/command routing. For AI routing, also add the key to the\nClassifier Output Parser enum.\n\n### 2. Conversation Memory\nRouter Memory (Postgres) gives the AI Classifier context across messages.\nFollow-up questions route correctly.\n\n### 3. Unified Routing\nThe AI Classifier routes to both agents (expenses, learning, deals)\nAND LLM backends (Groq, Brave, Perplexity).\n\n### Setup\nSee setup-guide.md for full post-import checklist.",
        "height": 600,
        "width": 500
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        8224,
        3648
      ],
      "id": "4502a13c-86c5-4d27-8247-d390de6580cb",
      "name": "Sticky Note - Overview"
    },
    {
      "parameters": {
        "content": "If stopped here \u2192\n[credentials-guide.md](YOUR_GITHUB_REPO_URL/blob/main/projects/n8n/credentials-guide.md#brave-search)",
        "height": 80,
        "width": 150
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        10200,
        4040
      ],
      "id": "b7e2c1a0-3f44-4e8d-9a12-5d6e8f0b1c2d",
      "name": "Sticky Note - Brave Setup"
    },
    {
      "parameters": {
        "content": "chatId: $json.chatId\ntext: $json.text\naction: $json.action\nworkflowId: $json.workflowId\nonError: continueOnFail\n\u2192 errors \u2192 Format Skill Response",
        "height": 150,
        "width": 200,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        9720,
        3540
      ],
      "id": "stn00001-0001-0001-0001-000000000001",
      "name": "Sticky Note - Run Skill Params"
    },
    {
      "parameters": {
        "content": "chatId: $json.chatId\ntext: $json.text\naction: $json.action\nworkflowId: $json.workflowId",
        "height": 120,
        "width": 200,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        10424,
        3600
      ],
      "id": "stn00002-0001-0001-0001-000000000001",
      "name": "Sticky Note - Run Skill AI Params"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "agent-available",
              "leftValue": "={{ $json.workflowId }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "isNotEmpty"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        10352,
        3640
      ],
      "id": "ifa00001-0001-0001-0001-000000000001",
      "name": "Agent Available?"
    }
  ],
  "connections": {
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Whitelist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Whitelist": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Workflow Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Normalize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize": {
      "main": [
        [
          {
            "node": "Route",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route": {
      "main": [
        [
          {
            "node": "Build Help",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Run Skill",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI Classifier",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Classifier": {
      "main": [
        [
          {
            "node": "LLM Route",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Classifier LLM": {
      "ai_languageModel": [
        [
          {
            "node": "AI Classifier",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Classifier Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Classifier",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Router Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Classifier",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "LLM Route": {
      "main": [
        [
          {
            "node": "Groq Reasoning",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Brave Search",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Perplexity Research",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Resolve Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolve Agent": {
      "main": [
        [
          {
            "node": "Agent Available?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Agent Available?": {
      "main": [
        [
          {
            "node": "Run Skill (AI)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Reasoning": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Reasoning LLM": {
      "ai_languageModel": [
        [
          {
            "node": "Groq Reasoning",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Brave Search": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Perplexity Research": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Response": {
      "main": [
        [
          {
            "node": "Send Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Skill": {
      "main": [
        [
          {
            "node": "Format Skill Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Skill (AI)": {
      "main": [
        [
          {
            "node": "Format Skill Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Skill Response": {
      "main": [
        [
          {
            "node": "Send Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Help": {
      "main": [
        [
          {
            "node": "Send Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Menu-Handler. Uses telegramTrigger, chatTrigger, executeWorkflowTrigger, chainLlm. Event-driven trigger; 28 nodes.

Source: https://github.com/runfish5/micro-services/blob/main/projects/n8n/10_steward/workflows/menu-handler.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

This comprehensive N8N automation template revolutionizes content creation by delivering a complete end-to-end solution for AI-powered blog generation. Transform simple ideas into fully SEO-optimized,

Slack Trigger, Telegram Trigger, Gmail Trigger +16
Slack & Telegram

Telegram Code. Uses lmChatOpenAi, outputParserAutofixing, outputParserStructured, telegramTrigger. Event-driven trigger; 43 nodes.

OpenAI Chat, Output Parser Autofixing, Output Parser Structured +4
Slack & Telegram

Telegram Code. Uses lmChatOpenAi, outputParserAutofixing, outputParserStructured, telegramTrigger. Event-driven trigger; 43 nodes.

OpenAI Chat, Output Parser Autofixing, Output Parser Structured +4
Slack & Telegram

SRT Translator. Uses formTrigger, executeWorkflowTrigger, form, telegramTrigger. Event-driven trigger; 34 nodes.

Form Trigger, Execute Workflow Trigger, Form +7
Slack & Telegram

Effortlessly track your expenses with MoneyMate, an n8n workflow that transforms receipts into organized financial insights.

HTTP Request, Telegram Trigger, Chain Llm +4