{"workflow":{"id":14051,"name":"Query expenses on Telegram with GPT-4.1 and Google Sheets","views":50,"recentViews":1,"totalViews":50,"createdAt":"2026-03-14T16:43:36.648Z","description":"# 💬 Chat with Your Finances on Telegram\n\nAsk questions like *“How much did I spend on food last month?”* and get instant answers from your financial data — directly in Telegram.\n\n\nThis workflow connects your **Google Sheets expense log** to an **AI-powered query engine** that understands natural language, resolves ambiguous categories and person names, and sends back a **clean formatted summary** in Telegram.\n\nNo spreadsheets. No dashboards.  \nJust **chat with your financial data**.\n\n---\n\n## ⚡ How it works\n\nSimply send a message like:\n\n- *How much did we spend on groceries last month?*\n- *Show me a breakdown by category for this week.*\n\nThe workflow automatically:\n\n1. **Parses your intent** using GPT-4.1-nano  \n2. **Resolves categories and person names** via mapping tables  \n3. **Filters and aggregates expense data** from Google Sheets  \n4. **Returns a formatted summary** directly in Telegram\n\nIf a category or person is unknown, the workflow uses AI to **suggest the closest match** and asks the user to confirm via **Telegram inline buttons**.\n\nConfirmed aliases are saved automatically, making the system **self-learning over time**.\n\n---\n\n## ✨ Key Features\n\n- **Natural language queries** in English and German  \n- **AI intent parsing** with GPT-4.1-nano (time range, person, category, filters)  \n- **Self-learning entity resolution** for categories and names  \n- **Interactive disambiguation** via Telegram inline buttons  \n- **Relative date support** (`this week`, `last month`, `this year`)  \n- **Group-by breakdowns** by category or person  \n- **Shared expense filtering** via `common_only` flag  \n- **Multi-user support** via Chat ID allowlist\n\n---\n\n## 📋 Requirements\n\nTo run this workflow you need:\n\n- **Telegram Bot** (created via `@BotFather`)\n- **OpenAI API key**\n- **Four Google Sheets**\n\nRequired sheets:\n\n- `expenses`\n- `expense_categories`\n- `categories_mapping`\n- `person_mapping`\n\n---\n\n## ⏱ Setup Time\n\nApprox. **15 minutes**\n\nAll required configuration steps are documented directly inside the workflow using **\"Action Required\" notes** in each workflow layer.\n\n---\n\n## Examples\n\n![image.png](fileId:4911)\n\n","workflow":{"id":"","meta":{"templateCredsSetupCompleted":false},"name":"Telegram Expense Tracker — Query Bot (Template)","tags":[],"nodes":[{"id":"58535881-40c5-4d75-82c6-f0faa9443e1a","name":"MSG | Telegram Inbound","type":"n8n-nodes-base.telegramTrigger","position":[2144,1088],"webhookId":"","parameters":{"updates":["message","callback_query"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"","name":"YOUR_TELEGRAM_CREDENTIAL"}},"typeVersion":1.1},{"id":"69f61c14-bd15-4c5a-b0b8-ada463bff839","name":"LLM | Parse Intent","type":"@n8n/n8n-nodes-langchain.openAi","position":[2880,1632],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4.1-nano","cachedResultName":"GPT-4.1-NANO"},"options":{},"messages":{"values":[{"role":"system","content":"=You are a financial intent parser.\nYour ONLY task is to convert a natural language finance question into structured JSON.\nYou must:\n- Return ONLY valid JSON.\n- Do NOT include explanations.\n- Do NOT include markdown.\n- Do NOT answer the question.\n- Do NOT guess missing information.\n- Do NOT add extra fields.\n\nThe user's first name is: {{ $('MSG | Telegram Inbound').item.json.message.from.first_name }}\nThe current year is: {{ new Date().getFullYear() }}\nThe current date is: {{ new Date().toISOString().split('T')[0] }}\n\nAlways return the following JSON structure:\n{\n  \"intent\": \"spending_query\",\n  \"time_reference\": \"last_week, this_week, last_month, this_month, last_year, this_year, or null\",\n  \"explicit_start_date\": \"YYYY-MM-DD or null\",\n  \"explicit_end_date\": \"YYYY-MM-DD or null\",\n  \"person\": \"string or null\",\n  \"category\": [\"string\"] or null,\n  \"common_only\": true, false, or null,\n  \"comparison\": \"previous_period, previous_month, previous_year, or null\",\n  \"group_by\": \"category, person, or null\"\n}\n\nInterpretation Rules:\n1. Date Handling (IMPORTANT):\n- If the user mentions a specific month without a year (e.g. \"february\", \"januar\"),\n  assume the current year and set explicit_start_date and explicit_end_date accordingly.\n  Example: \"february\" → explicit_start_date: \"2026-02-01\", explicit_end_date: \"2026-02-28\"\n- If the user refers to relative time (e.g., last week, this month, last month, this year, etc.), \n  set the correct value in \"time_reference\".\n- DO NOT calculate actual dates for relative time references.\n- Leave explicit_start_date and explicit_end_date as null for relative time references.\n- If the user provides an explicit date range (e.g., 01.01.2026 - 31.01.2026),\n  set explicit_start_date and explicit_end_date accordingly,\n  and set time_reference to null.\n- If no time reference is mentioned → set all three fields to null.\n\n2. Person Handling:\n- If user says \"I\", \"me\", \"ich\", \"mir\" → use \"{{ $('MSG | Telegram Inbound').item.json.message.from.first_name }}\"\n- If user says \"we\", \"wir\", \"uns\", \"beide\" → null (refers to both persons, no filter needed).\n- If a specific name or nickname is mentioned that refers to another person → use that exact name as written.\n- If no person is mentioned → null.\n- NEVER invent or guess a person name.\n- The value for \"person\" must always be either the mentioned name/nickname, \"{{ $('MSG | Telegram Inbound').item.json.message.from.first_name }}\", or null.\n\n3. category:\n- If one category is mentioned, return it as a single-element array.\n- If multiple categories are mentioned, return all of them as an array.\n- Use lowercase strings.\n- If none mentioned → null.\n\n4. Common Expense Handling (VERY IMPORTANT):\nSet \"common_only\" to true if the user explicitly refers to shared expenses.\nThis includes words or phrases such as:\n- shared\n- common\n- joint\n- together\n- gemeinschaftlich\n- gemeinsam\n- gemeinsame ausgaben\n- geteilte ausgaben\n- für uns\n- zusammen\nIf the user explicitly says:\n- \"für gemeinsame Ausgaben\"\n- \"für gemeinsame Kosten\"\nyou MUST set \"common_only\" to true.\nSet \"common_only\" to false if the user explicitly refers to private expenses.\nThis includes:\n- private\n- persönlich\n- eigene ausgaben\n- nur für sich\n- privat\nIf shared/private is NOT explicitly mentioned → set \"common_only\" to null.\nNever assume.\n\n5. Comparison:\n- If user compares with previous month → \"previous_month\"\n- If compares with previous period → \"previous_period\"\n- If compares with previous year → \"previous_year\"\n- Otherwise → null\n\n6. Grouping:\n- If user asks for breakdown by category → \"category\"\n- If breakdown by person → \"person\"\n- Otherwise → null\n\nReturn ONLY JSON."},{"content":"={{ $json.message.text }}"}]}},"credentials":{"openAiApi":{"id":"","name":"YOUR_OPENAI_CREDENTIAL"}},"typeVersion":1.4},{"id":"1f1984d4-cc31-4730-8354-69c6ec425bbe","name":"JS | Extract Intent JSON","type":"n8n-nodes-base.code","position":[3232,1632],"parameters":{"jsCode":"const rawContent = $input.first().json.message?.content || $input.first().json.choices?.[0]?.message?.content || '{}';\nlet parsed = {};\ntry {\n  const cleaned = rawContent.replace(/```json|```/g, '').trim();\n  parsed = JSON.parse(cleaned);\n} catch(e) {\n  parsed = { intent: 'spending_query', start_date: null, end_date: null, person: null, category: null, common_only: null, comparison: null, group_by: null };\n}\nreturn [{ json: parsed }];"},"typeVersion":2},{"id":"4e830963-ede6-4d56-b328-7f3119040143","name":"GS | Load Expenses","type":"n8n-nodes-base.googleSheets","position":[9824,1440],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"expenses"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.4},{"id":"4271bf57-4b8d-4f68-8896-2d55f162161e","name":"GS | Load Categories","type":"n8n-nodes-base.googleSheets","position":[9824,1152],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"expense_categories"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.4},{"id":"21d72a8f-e9cd-4fac-b832-f0804777d270","name":"JS | Filter & Aggregate","type":"n8n-nodes-base.code","position":[10576,1264],"parameters":{"jsCode":"// =============================\n// Date Engine\n// =============================\n\nconst now = new Date();\n\nfunction normalizeDate(date) {\n  const d = new Date(date);\n  if (isNaN(d)) return null;\n  d.setHours(0,0,0,0);\n  return d;\n}\n\nfunction getDateRange(timeReference) {\n\n  switch (timeReference) {\n\n    case \"this_month\":\n      return {\n        start: normalizeDate(new Date(now.getFullYear(), now.getMonth(), 1)),\n        end: normalizeDate(now)\n      };\n\n    case \"last_month\":\n      return {\n        start: normalizeDate(new Date(now.getFullYear(), now.getMonth() - 1, 1)),\n        end: normalizeDate(new Date(now.getFullYear(), now.getMonth(), 0))\n      };\n\n    case \"this_year\":\n      return {\n        start: normalizeDate(new Date(now.getFullYear(), 0, 1)),\n        end: normalizeDate(now)\n      };\n\n    case \"last_year\":\n      return {\n        start: normalizeDate(new Date(now.getFullYear() - 1, 0, 1)),\n        end: normalizeDate(new Date(now.getFullYear() - 1, 11, 31))\n      };\n\n    case \"last_week\":\n      const day = now.getDay();\n      const diffToMonday = (day + 6) % 7;\n\n      const lastMonday = new Date(now);\n      lastMonday.setDate(now.getDate() - diffToMonday - 7);\n\n      const lastSunday = new Date(lastMonday);\n      lastSunday.setDate(lastMonday.getDate() + 6);\n\n      return {\n        start: normalizeDate(lastMonday),\n        end: normalizeDate(lastSunday)\n      };\n\n    case \"this_week\":\n      const currentDay = now.getDay();\n      const diff = (currentDay + 6) % 7;\n\n      const monday = new Date(now);\n      monday.setDate(now.getDate() - diff);\n\n      return {\n        start: normalizeDate(monday),\n        end: normalizeDate(now)\n      };\n\n    default:\n      return { start: null, end: null };\n  }\n}\n\nfunction formatDate(date) {\n  if (!date) return null;\n  return date.toISOString().split('T')[0];\n}\n\n// =============================\n// Retrieve Intent\n// =============================\n\nconst intent = $('JS | Extract Intent JSON').first().json;\nconst edit3 = $('SET | Assemble Resolved Intent').first().json;\n\n// IMPORTANT: overwrite values if edited\nintent.person = edit3.person || intent.person;\nintent.category = edit3.category || intent.category;\n\n// =============================\n// Load & Normalize Data\n// =============================\n\nconst expenseItems = $('GS | Load Expenses').all().map(i => ({\n  date: i.json.date,\n  amount: parseFloat(i.json.amount) || 0,\n  category: i.json.category?.toLowerCase() || null,\n  description: i.json.description,\n  common_expense: i.json.common_expense,\n  person: i.json.Person?.toLowerCase() || null\n}));\n\n// =============================\n// Date Handling\n// =============================\n\nlet startDate = null;\nlet endDate = null;\n\nif (intent.time_reference) {\n  const range = getDateRange(intent.time_reference);\n  startDate = range.start;\n  endDate = range.end;\n}\n\nif (intent.explicit_start_date) {\n  startDate = normalizeDate(intent.explicit_start_date);\n}\n\nif (intent.explicit_end_date) {\n  endDate = normalizeDate(intent.explicit_end_date);\n}\n\nconst formattedStart = formatDate(startDate);\nconst formattedEnd = formatDate(endDate);\n\n// =============================\n// Other Filters\n// =============================\n\nconst filterPerson = intent.person ? intent.person.toLowerCase() : null;\n\nconst filterCategories = (() => {\n  const c = intent.category;\n  if (!c) return [];\n  if (Array.isArray(c)) {\n    return c.map(x => String(x).trim().toLowerCase()).filter(Boolean);\n  }\n  return [String(c).trim().toLowerCase()].filter(Boolean);\n})();\n\nconst filterCommon = intent.common_only;\nconst groupBy = intent.group_by;\n\n// =============================\n// Apply Filters\n// =============================\n\nconst filtered = expenseItems.filter(row => {\n\n  if (!row.date) return false;\n\n  const rowDate = normalizeDate(row.date);\n  if (!rowDate) return false;\n\n  if (startDate && rowDate < startDate) return false;\n  if (endDate && rowDate > endDate) return false;\n\n  if (filterPerson && row.person !== filterPerson) return false;\n\n  if (filterCategories.length > 0) {\n    if (!row.category) return false;\n    if (!filterCategories.includes(row.category)) return false;\n  }\n\n  if (filterCommon !== null && filterCommon !== undefined) {\n\n    const isCommon =\n      String(row.common_expense).toLowerCase() === 'true' ||\n      row.common_expense === true ||\n      row.common_expense === 1;\n\n    if (filterCommon && !isCommon) return false;\n    if (!filterCommon && isCommon) return false;\n  }\n\n  return true;\n\n});\n\n// =============================\n// Aggregations\n// =============================\n\nconst total = filtered.reduce((sum, row) => sum + row.amount, 0);\n\n// Category breakdown\nlet categoryBreakdown = null;\n\nif (groupBy === \"category\") {\n\n  const breakdown = {};\n\n  filtered.forEach(row => {\n\n    const cat = row.category || \"uncategorized\";\n\n    breakdown[cat] = (breakdown[cat] || 0) + row.amount;\n\n  });\n\n  categoryBreakdown = breakdown;\n}\n\n// Person breakdown\nlet personBreakdown = null;\n\nif (groupBy === \"person\") {\n\n  const breakdown = {};\n\n  filtered.forEach(row => {\n\n    const person = row.person || \"unknown\";\n\n    breakdown[person] = (breakdown[person] || 0) + row.amount;\n\n  });\n\n  personBreakdown = breakdown;\n}\n\n// =============================\n// Return Result\n// =============================\n\nreturn [{\n  json: {\n    intent,\n    total: Math.round(total * 100) / 100,\n    count: filtered.length,\n    categoryBreakdown,\n    personBreakdown,\n    period: {\n      start: formattedStart,\n      end: formattedEnd\n    },\n    filters: {\n      person: intent.person,\n      category: intent.category,\n      common_only: intent.common_only\n    }\n  }\n}];"},"typeVersion":2},{"id":"b24a37e4-d82f-43e6-b343-e91f7f838d19","name":"JS | Format Response Message","type":"n8n-nodes-base.code","position":[11056,1264],"parameters":{"jsCode":"const data = $input.first().json;\nconst filters = data.filters || {};\nconst period = data.period || {};\n\nlet lines = [];\n\n// =============================\n// Header\n// =============================\n\nlines.push('📊 *Expense Summary*');\nlines.push('');\n\n// =============================\n// Period Display (NEW)\n// =============================\n\nif (period.start || period.end) {\n  const from = period.start || 'Beginning';\n  const to = period.end || 'Today';\n  lines.push(`📅 Period: ${from} → ${to}`);\n} else {\n  lines.push(`📅 Period: All time`);\n}\n\n// =============================\n// Applied filters\n// =============================\n\nif (filters.person) lines.push(`👤 Person: ${filters.person}`);\nif (filters.category) lines.push(`🏷️ Category: ${filters.category}`);\n\nif (filters.common_only !== null && filters.common_only !== undefined) {\n  lines.push(`🔗 Common expenses only: ${filters.common_only ? 'Yes' : 'No'}`);\n}\n\nlines.push('');\nlines.push(`💰 *Total: €${data.total.toFixed(2)}*`);\nlines.push(`📝 Transactions: ${data.count}`);\n\n// =============================\n// Category breakdown\n// =============================\n\nif (data.categoryBreakdown) {\n  lines.push('');\n  lines.push('*By Category:*');\n\n  const sorted = Object.entries(data.categoryBreakdown)\n    .sort((a, b) => b[1] - a[1]);\n\n  sorted.forEach(([cat, amt]) => {\n    const pct = data.total > 0\n      ? ((amt / data.total) * 100).toFixed(1)\n      : 0;\n\n    lines.push(`  • ${cat}: $${amt.toFixed(2)} (${pct}%)`);\n  });\n}\n\n// =============================\n// Person breakdown\n// =============================\n\nif (data.personBreakdown) {\n  lines.push('');\n  lines.push('*By Person:*');\n\n  const sorted = Object.entries(data.personBreakdown)\n    .sort((a, b) => b[1] - a[1]);\n\n  sorted.forEach(([person, amt]) => {\n    const pct = data.total > 0\n      ? ((amt / data.total) * 100).toFixed(1)\n      : 0;\n\n    lines.push(`  • ${person}: $${amt.toFixed(2)} (${pct}%)`);\n  });\n}\n\n// =============================\n// Comparison placeholder\n// =============================\n\nif (data.comparison) {\n  lines.push('');\n  lines.push(`📈 Comparison: [Feature coming soon]`);\n}\n\n// =============================\n// Empty state\n// =============================\n\nif (data.count === 0) {\n  lines.push('');\n  lines.push('_No expenses found for the given filters._');\n}\n\nreturn [{ json: { message: lines.join('\\n') } }];"},"typeVersion":2},{"id":"c7dc9c2c-8bc0-4b0a-a988-27a966b3f814","name":"TG | Send Reply","type":"n8n-nodes-base.telegram","position":[11312,1264],"webhookId":"","parameters":{"text":"={{ $json.message }}","chatId":"={{ $('MSG | Telegram Inbound').first().json.message.chat.id }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false,"reply_to_message_id":"={{ $('MSG | Telegram Inbound').first().json.message.message_id }}"}},"credentials":{"telegramApi":{"id":"","name":"YOUR_TELEGRAM_CREDENTIAL"}},"typeVersion":1.2},{"id":"4876799b-af52-4218-80aa-7603258ff084","name":"MERGE | Combine Expenses + Categories","type":"n8n-nodes-base.merge","position":[10144,1264],"parameters":{"mode":"chooseBranch"},"typeVersion":3.2},{"id":"db13a254-5fde-42e4-9e82-2060a04451f0","name":"IF | User Authorized?","type":"n8n-nodes-base.if","position":[2528,1072],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"or","conditions":[{"id":"0f85f7d5-8b7e-4bcd-ae10-d7a1785192c4","operator":{"type":"number","operation":"equals"},"leftValue":"={{ $json.message.chat.id }}","rightValue":1000000000},{"id":"2d18f8cf-2910-4e20-b2f3-16a9ef04e63e","operator":{"type":"number","operation":"equals"},"leftValue":"={{ $json.message.chat.id }}","rightValue":1000000001}]}},"typeVersion":2.2},{"id":"7a76b7d6-f533-4785-b822-8d7ac464d883","name":"SPLIT | Split Categories","type":"n8n-nodes-base.splitOut","position":[4016,768],"parameters":{"options":{},"fieldToSplitOut":"category"},"typeVersion":1},{"id":"8e963faf-3079-447d-bfd9-89eff8da207e","name":"GS | Read Category Mapping","type":"n8n-nodes-base.googleSheets","position":[4016,1072],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"categories_mapping"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.7},{"id":"e992cd5e-ba4e-4ab5-b885-14c55546d0a3","name":"MERGE | Join Categories with Mapping","type":"n8n-nodes-base.merge","position":[4272,768],"parameters":{"mode":"combineBySql","query":"SELECT * FROM input1 LEFT JOIN input2 ON input1.category = input2.find","options":{}},"typeVersion":3.2},{"id":"58c889ef-e918-43d4-a7a3-1a47bf890ffc","name":"TG | Confirm Category Suggestion","type":"n8n-nodes-base.telegram","position":[6224,368],"webhookId":"","parameters":{"chatId":"={{ $('MSG | Telegram Inbound').item.json.message.chat.id }}","message":"=I couldn’t find the category \"{{ $('IF | Category Known?').item.json.category_new }}\".\n\nDid you mean \"{{ $json.content }}\"?\n\n✅ Yes  \n❌ No","options":{"appendAttribution":false},"operation":"sendAndWait","approvalOptions":{"values":{"approvalType":"double","approveLabel":"✅ Yes","disapproveLabel":"❌ No"}}},"credentials":{"telegramApi":{"id":"","name":"YOUR_TELEGRAM_CREDENTIAL"}},"typeVersion":1.2},{"id":"fd9c3d1c-223a-44d8-afbf-4773a11d09bd","name":"GS | Read Allowed Categories","type":"n8n-nodes-base.googleSheets","position":[4464,1072],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"expense_categories"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.7},{"id":"2f1f1de8-cae3-4792-920c-ba490986019e","name":"SET | Normalize Category","type":"n8n-nodes-base.set","position":[4464,768],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8f458013-1006-4634-a1c8-aedff820a48f","name":"category_new","type":"string","value":"={{ $json.replace ?? $json.category }}"}]}},"typeVersion":3.4},{"id":"7a819214-50e5-460a-bd4d-a546eb68dc20","name":"MERGE | Check Category against Allowed","type":"n8n-nodes-base.merge","position":[4720,768],"parameters":{"mode":"combineBySql","query":"SELECT * FROM input1\n  \nLEFT JOIN input2 ON input1.category_new = input2.category","options":{}},"typeVersion":3.2,"alwaysOutputData":false},{"id":"ed0de8c5-8c55-49f2-96a0-973b49b95d6a","name":"IF | Category Known?","type":"n8n-nodes-base.if","position":[4960,768],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"e329be08-8c46-4898-9480-5946735ad54d","operator":{"type":"string","operation":"notExists","singleValue":true},"leftValue":"={{ $json.description }}","rightValue":""}]}},"typeVersion":2.3,"alwaysOutputData":false},{"id":"9ecd305a-5e42-43f1-91fa-21fbb0d89e53","name":"LLM | Classify Category","type":"@n8n/n8n-nodes-langchain.openAi","position":[5712,368],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4.1-nano","cachedResultName":"GPT-4.1-NANO"},"options":{},"messages":{"values":[{"role":"system","content":"=You are a strict category classification system.\n\nYour task:\nMap the given input category to exactly ONE category from the allowed category list.\n\nRules:\n- You MUST select one category from the allowed list.\n- Do NOT invent new categories.\n- Do NOT return explanations.\n- Do NOT return multiple categories.\n- Output ONLY the exact category name from the allowed list.\n- Matching must be case-insensitive.\n- Choose the closest semantic match if there is no exact match.\n\nInput category:\n{{ $('IF | Category Known?').item.json.category_new }}\n\nAllowed categories:\n{{ $json.category }}"}]}},"credentials":{"openAiApi":{"id":"","name":"YOUR_OPENAI_CREDENTIAL"}},"typeVersion":1.4},{"id":"73085ca0-da81-4f8f-a232-5680c7d88b88","name":"MERGE | Combine Categories with List","type":"n8n-nodes-base.merge","position":[5216,672],"parameters":{"mode":"combine","options":{},"combineBy":"combineAll"},"typeVersion":3.2},{"id":"19fe45dc-435b-4e70-9b7a-cd7c0bedd41e","name":"SET | Extract LLM Category","type":"n8n-nodes-base.set","position":[5968,368],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{ $json.message }}"},"typeVersion":3.4},{"id":"20b22d0e-35bf-476f-9aba-e2abb14f0377","name":"IF | Category Suggestion Accepted?","type":"n8n-nodes-base.if","position":[6464,368],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4fb343c7-9eb2-4491-b017-3637fb543564","operator":{"type":"boolean","operation":"equals"},"leftValue":"={{ $json.data.approved }}","rightValue":true}]}},"typeVersion":2.3},{"id":"1d692432-6601-47f1-9bdd-cafd50aeef5c","name":"GS | Save Category Mapping","type":"n8n-nodes-base.googleSheets","position":[7968,368],"parameters":{"columns":{"value":{"find":"={{ $json.old }}","replace":"={{ $json.new }}"},"schema":[{"id":"find","type":"string","display":true,"required":false,"displayName":"find","defaultMatch":false,"canBeUsedToMatch":true},{"id":"replace","type":"string","display":true,"required":false,"displayName":"replace","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"categories_mapping"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.7},{"id":"750a9069-a57b-4b46-8725-42367602aad2","name":"MERGE | Loop Entry (Category)","type":"n8n-nodes-base.merge","position":[5712,768],"parameters":{},"typeVersion":3.2},{"id":"20498665-76a1-45b8-978f-e92e0fc19ed1","name":"SET | Set Resolved Category","type":"n8n-nodes-base.set","position":[5968,768],"parameters":{"options":{},"assignments":{"assignments":[{"id":"47a00b45-f580-4568-9913-b2359e1c1d8c","name":"category_new","type":"string","value":"={{ $json.replace ?? $('IF | Category Known?').item.json.category_new}}"}]}},"typeVersion":3.4},{"id":"e6824c4c-a839-40d0-b334-40f19aad19d0","name":"SET | Assemble Resolved Intent","type":"n8n-nodes-base.set","position":[9472,1264],"parameters":{"options":{},"assignments":{"assignments":[{"id":"dc8b496a-4e1a-4ba3-9180-61b77a616b99","name":"intent","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.intent }}"},{"id":"1e76280f-f49b-4225-ba90-fccc0ba3d9f2","name":"time_reference","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.time_reference }}"},{"id":"1b10b1a5-e35d-4e13-8a28-945271eb4cd6","name":"explicit_start_date","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.explicit_start_date }}"},{"id":"51c694b2-c10b-485d-8e1e-dedd797308a9","name":"explicit_end_date","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.explicit_end_date }}"},{"id":"56a2b084-547f-412f-b534-4c2a97ec52c8","name":"person","type":"string","value":"={{ $json.person_new }}"},{"id":"aa1b02a7-6908-4ba0-b8c2-a74b15516b40","name":"category","type":"array","value":"={{ $json.category_new }}"},{"id":"4bd911ba-a8e3-423c-aa2e-eab59e16a33a","name":"common_only","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.common_only }}"},{"id":"720e91ea-fc42-48b4-af78-1853736d8720","name":"comparison","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.comparison }}"},{"id":"27656405-d197-4f6e-b1d8-f90a72351f20","name":"group_by","type":"string","value":"={{ $('JS | Extract Intent JSON').item.json.group_by }}"}]}},"typeVersion":3.4},{"id":"cc31446d-2ffb-4411-afd7-64e69182b448","name":"AGG | Aggregate Category List","type":"n8n-nodes-base.aggregate","position":[4720,1072],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"category"}]}},"typeVersion":1},{"id":"6f2ace60-279f-40ce-8459-53a13a603748","name":"LOOP | Iterate Categories","type":"n8n-nodes-base.splitInBatches","position":[5472,768],"parameters":{"options":{}},"typeVersion":3},{"id":"165edc36-f6bd-4231-a1e4-bd7c7cd4ecea","name":"SET | Set New+Old Category (LLM)","type":"n8n-nodes-base.set","position":[7216,368],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5f52894c-c285-46f0-822d-44665a58555f","name":"new","type":"string","value":"={{ $('SET | Extract LLM Category').item.json.content }}"},{"id":"e02f6b7f-c27d-4620-84e4-346dcb5f26f0","name":"old","type":"string","value":"={{ $('LOOP | Iterate Categories').item.json.category_new }}"}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"8294d338-81df-4799-8d83-335699eb38d9","name":"JS | Build Category Inline Buttons","type":"n8n-nodes-base.code","position":[6720,176],"parameters":{"jsCode":"const items = $('AGG | Aggregate Category List').first().json.category;\nif (!Array.isArray(items)) {\n  throw new Error('Expected category to be an array');\n}\n\nconst buttons = items.map(item => ([{\n  text: String(item),\n  callback_data: String(item)\n}]));\n\nreturn [{\n  json: {\n    inline_keyboard: buttons,\n    resumeUrl: $execution.resumeUrl\n  }\n}];"},"typeVersion":2},{"id":"e7a92e17-a097-4e67-8ba0-aa2073aeefb1","name":"WAIT | Wait for Category Selection","type":"n8n-nodes-base.wait","position":[7216,176],"webhookId":"","parameters":{"resume":"webhook","options":{},"httpMethod":"POST"},"typeVersion":1.1},{"id":"d5c9afc3-2245-4a93-9c66-38edc4c0f4a2","name":"HTTP | Send Category Selection Message","type":"n8n-nodes-base.httpRequest","position":[6960,176],"parameters":{"url":"https://api.telegram.org/bot{{YOUR_BOT_TOKEN}}/sendMessage","method":"POST","options":{},"jsonBody":"={\n  \"chat_id\": \"{{ $('MSG | Telegram Inbound').item.json.message.chat.id }}\",\n  \"text\": \"Bitte wähle eine Kategorie:<a href='{{ $json.resumeUrl }}'>​</a>\",\n  \"parse_mode\": \"HTML\",\n  \"reply_markup\": {{ JSON.stringify({ \"inline_keyboard\": $json.inline_keyboard }) }}\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.3},{"id":"33dba25d-9b17-4da1-8463-92dbad2c0ff3","name":"SET | Read Callback Body (Cat.)","type":"n8n-nodes-base.set","position":[7472,176],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{ $json.body}}"},"typeVersion":3.4},{"id":"e11d27e9-66ea-4cde-a108-3c38b5fea75b","name":"SET | Set New+Old Category (Selection)","type":"n8n-nodes-base.set","position":[7472,368],"parameters":{"options":{},"assignments":{"assignments":[{"id":"e34ab1c9-3985-432b-9637-6a695fbf5931","name":"new","type":"string","value":"={{ $json.category }}"},{"id":"b3f6ce98-c6bc-4fea-a581-d1abcd087df4","name":"old","type":"string","value":"={{ $('LOOP | Iterate Categories').item.json.category_new }}"}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"e765fbf0-81a6-4117-9fbf-8c5c4d0f6c90","name":"MERGE | Combine Category Mapping Entries","type":"n8n-nodes-base.merge","position":[7712,368],"parameters":{},"typeVersion":3.2},{"id":"dada58e6-2abc-4cec-84c2-4bd92994e796","name":"HTTP | Forward Category Selection","type":"n8n-nodes-base.httpRequest","position":[3312,496],"parameters":{"url":"={{ $json.resumeUrl }}","method":"POST","options":{},"jsonBody":"={\n  \"category\": \"{{ $json.category }}\"\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.3},{"id":"76197f7e-8f0f-46d5-84b4-c9c6bb735668","name":"TG | Confirm Category Selection","type":"n8n-nodes-base.telegram","position":[3504,496],"webhookId":"","parameters":{"text":"=Du hast \" {{ $('MSG | Telegram Inbound').item.json.callback_query.data }}\" ausgewählt\"","chatId":"={{ $('MSG | Telegram Inbound').item.json.callback_query.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"","name":"YOUR_TELEGRAM_CREDENTIAL"}},"typeVersion":1.2},{"id":"883bf86d-3fac-461a-a9b7-dcc0018eb20f","name":"JS | Read Category Callback","type":"n8n-nodes-base.code","position":[3104,496],"parameters":{"jsCode":"const callbackData = $json.callback_query.data;\nconst text = $json.callback_query.message.text;\nconst entities = $json.callback_query.message.entities;\n\n// URL aus den message entities auslesen\nconst urlEntity = entities.find(e => e.type === 'text_link');\nconst resumeUrl = urlEntity.url;\n\nreturn [{\n  json: {\n    category: callbackData,\n    resumeUrl: resumeUrl\n  }\n}];"},"typeVersion":2},{"id":"0e0c0fc1-c577-4e31-a62e-2bef9ef22815","name":"IF | Message or Callback?","type":"n8n-nodes-base.if","position":[2352,1088],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"69655a65-f86e-4666-8f8f-d9cc2fda74b2","operator":{"type":"object","operation":"exists","singleValue":true},"leftValue":"={{ $json.message }}","rightValue":"="}]}},"typeVersion":2.3},{"id":"4233a9ba-e3a9-49c7-8f07-1d36fa3fec81","name":"IF | Category Present?","type":"n8n-nodes-base.if","position":[3824,976],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"b875ecb6-7b43-4083-8591-bec82fb6a22b","operator":{"type":"string","operation":"notExists","singleValue":true},"leftValue":"={{ $json.category[0] }}","rightValue":""}]}},"typeVersion":2.3},{"id":"449ced93-3de6-4bf4-8e71-cb0acb48a43e","name":"MERGE | Combine Category + Person","type":"n8n-nodes-base.merge","position":[8832,1248],"parameters":{"numberInputs":3},"typeVersion":3.2},{"id":"f98b58b7-483e-495b-95c1-aa5a9fa457c4","name":"AGG | Aggregate Resolved Categories","type":"n8n-nodes-base.aggregate","position":[6224,768],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"category_new"}]}},"typeVersion":1},{"id":"50f4587d-754a-4bb3-888b-b6e084ee6237","name":"IF | Person Present?","type":"n8n-nodes-base.if","position":[3760,2096],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"b875ecb6-7b43-4083-8591-bec82fb6a22b","operator":{"type":"string","operation":"notExists","singleValue":true},"leftValue":"={{ $json.person }}","rightValue":""}]}},"typeVersion":2.3},{"id":"85f203b8-bdf7-4346-aceb-30a8388dc4cf","name":"SPLIT | Split Persons","type":"n8n-nodes-base.splitOut","position":[3968,2064],"parameters":{"options":{},"fieldToSplitOut":"person"},"typeVersion":1},{"id":"7657a339-c559-4327-bc25-5fda098783f3","name":"MERGE | Join Persons with Mapping","type":"n8n-nodes-base.merge","position":[4224,2064],"parameters":{"mode":"combineBySql","query":"SELECT * FROM input1 LEFT JOIN input2 ON input1.category = input2.find","options":{}},"typeVersion":3.2},{"id":"286c2311-d948-4dd0-92bb-81231cb895ea","name":"SET | Normalize Person","type":"n8n-nodes-base.set","position":[4416,2064],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8f458013-1006-4634-a1c8-aedff820a48f","name":"person_new","type":"string","value":"={{ $json.replace ?? $json.person }}"}]}},"typeVersion":3.4},{"id":"fa32c88e-fb58-483a-8159-bc68edbeebcd","name":"MERGE | Check Person against Allowed","type":"n8n-nodes-base.merge","position":[4704,2048],"parameters":{"mode":"combineBySql","query":"SELECT * FROM input1\n  \nLEFT JOIN input2 ON input1.person_new = input2.person","options":{}},"typeVersion":3.2,"alwaysOutputData":false},{"id":"8ed005b0-aa2a-4052-868a-424d6df8d83e","name":"IF | Person Known?","type":"n8n-nodes-base.if","position":[4944,2048],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"e329be08-8c46-4898-9480-5946735ad54d","operator":{"type":"string","operation":"notExists","singleValue":true},"leftValue":"={{ $json.description }}","rightValue":""}]}},"typeVersion":2.3,"alwaysOutputData":false},{"id":"2f3cf76a-d852-4479-a91a-4d93bdcb8e28","name":"MERGE | Combine Persons with List","type":"n8n-nodes-base.merge","position":[5200,2048],"parameters":{"mode":"combine","options":{},"combineBy":"combineAll"},"typeVersion":3.2},{"id":"9db7a679-849e-46a4-8c12-9c9296e00d4c","name":"AGG | Aggregate Person List","type":"n8n-nodes-base.aggregate","position":[4912,2352],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"person"}]}},"typeVersion":1},{"id":"82d59267-2594-498f-863b-f35116802032","name":"GS | Read Person Mapping","type":"n8n-nodes-base.googleSheets","position":[3968,2368],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"person_mapping"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.7},{"id":"16747ce4-9d18-438d-a8df-df00508908c1","name":"GS | Read Allowed Persons","type":"n8n-nodes-base.googleSheets","position":[4416,2368],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":1157427829,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"list_persons"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"person_mapping"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.7},{"id":"fa8b6b35-8747-40b8-9639-5131f279c0cb","name":"TG | Confirm Person Suggestion","type":"n8n-nodes-base.telegram","position":[6208,2448],"webhookId":"","parameters":{"chatId":"={{ $('MSG | Telegram Inbound').item.json.message.chat.id }}","message":"=I couldn’t find the person \"{{ $('IF | Person Known?').item.json.person_new }}\".\n\nDid you mean \"{{ $json.content }}\"?\n\n✅ Yes  \n❌ No","options":{"appendAttribution":false},"operation":"sendAndWait","approvalOptions":{"values":{"approvalType":"double","approveLabel":"✅ Yes","disapproveLabel":"❌ No"}}},"credentials":{"telegramApi":{"id":"","name":"YOUR_TELEGRAM_CREDENTIAL"}},"typeVersion":1.2},{"id":"fa9fc8ee-c15e-4f4f-9af2-8a5dd626d788","name":"LLM | Classify Person","type":"@n8n/n8n-nodes-langchain.openAi","position":[5696,2448],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4.1-nano","cachedResultName":"GPT-4.1-NANO"},"options":{},"messages":{"values":[{"role":"system","content":"=You are a strict person classification system.\n\nYour task:\nMap the given input name to exactly ONE person from the allowed person list.\n\nRules:\n\n* You MUST select one person from the allowed list.\n* Do NOT invent new persons.\n* Do NOT return explanations.\n* Do NOT return multiple persons.\n* Output ONLY the exact person name from the allowed list.\n* Matching must be case-insensitive.\n* Choose the closest semantic match if there is no exact match.\n\nInput name:\n{{ $('IF | Person Known?').item.json.person_new }}\n\nAllowed persons:\n{{ $json.person }}\n"}]}},"credentials":{"openAiApi":{"id":"","name":"YOUR_OPENAI_CREDENTIAL"}},"typeVersion":1.4},{"id":"ef710337-260f-495c-97aa-7ccb5420b7dc","name":"SET | Extract LLM Person","type":"n8n-nodes-base.set","position":[5952,2448],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{ $json.message }}"},"typeVersion":3.4},{"id":"fd5713f9-9501-420f-9d12-bb8b84fda620","name":"IF | Person Suggestion Accepted?","type":"n8n-nodes-base.if","position":[6448,2448],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4fb343c7-9eb2-4491-b017-3637fb543564","operator":{"type":"boolean","operation":"equals"},"leftValue":"={{ $json.data.approved }}","rightValue":true}]}},"typeVersion":2.3},{"id":"262227e8-5564-4caf-a833-edc83bd36894","name":"GS | Save Person Mapping","type":"n8n-nodes-base.googleSheets","position":[8176,1904],"parameters":{"columns":{"value":{"find":"={{ $json.old }}","replace":"={{ $json.new }}"},"schema":[{"id":"find","type":"string","display":true,"required":false,"displayName":"find","defaultMatch":false,"canBeUsedToMatch":true},{"id":"replace","type":"string","display":true,"required":false,"displayName":"replace","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"YOUR_SPREADSHEET_ID","cachedResultUrl":"https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID","cachedResultName":"person_mapping"}},"credentials":{"googleSheetsOAuth2Api":{"id":"","name":"YOUR_GOOGLE_SHEETS_CREDENTIAL"}},"typeVersion":4.7},{"id":"e6850bcd-ec85-4a14-ae06-73878206a278","name":"LOOP | Iterate Persons","type":"n8n-nodes-base.splitInBatches","position":[5456,2048],"parameters":{"options":{}},"typeVersion":3},{"id":"741e158c-14ed-4ff1-aba3-27b0f648ab20","name":"SET | Set New+Old Person (LLM)","type":"n8n-nodes-base.set","position":[7664,2304],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5f52894c-c285-46f0-822d-44665a58555f","name":"new","type":"string","value":"={{ $('SET | Extract LLM Person').item.json.content }}"},{"id":"e02f6b7f-c27d-4620-84e4-346dcb5f26f0","name":"old","type":"string","value":"={{ $('LOOP | Iterate Persons').item.json.person_new }}"}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"41280f1e-9534-4947-908a-41a7caef3397","name":"JS | Build Person Inline Buttons","type":"n8n-nodes-base.code","position":[6672,1712],"parameters":{"jsCode":"const items = $('AGG | Aggregate Person List').first().json.person;\n\nif (!Array.isArray(items)) {\n  throw new Error('Expected person to be an array');\n}\n\nconst buttons = items.map(item => ([{\n  text: String(item),\n  callback_data: String(item)\n}]));\n\nreturn [{\n  json: {\n    inline_keyboard: buttons,\n    resumeUrl: $execution.resumeUrl\n  }\n}];"},"typeVersion":2},{"id":"5f9c0563-ee99-4147-9081-f499af2bb507","name":"WAIT | Wait for Person Selection","type":"n8n-nodes-base.wait","position":[7168,1712],"webhookId":"","parameters":{"resume":"webhook","options":{},"httpMethod":"POST"},"typeVersion":1.1},{"id":"5b86154e-57b0-4b2d-a7d7-1e11cc878b67","name":"HTTP | Send Person Selection Message","type":"n8n-nodes-base.httpRequest","position":[6912,1712],"parameters":{"url":"https://api.telegram.org/bot{{YOUR_BOT_TOKEN}}/sendMessage","method":"POST","options":{},"jsonBody":"={\n  \"chat_id\": \"{{ $('MSG | Telegram Inbound').item.json.message.chat.id }}\",\n  \"text\": \"Bitte wähle eine Person:<a href='{{ $json.resumeUrl }}'>​</a>\",\n  \"parse_mode\": \"HTML\",\n  \"reply_markup\": {{ JSON.stringify({ \"inline_keyboard\": $json.inline_keyboard }) }}\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.3},{"id":"b879f1c5-ffb3-45b6-b7f5-1b772b431643","name":"SET | Read Callback Body (Person)","type":"n8n-nodes-base.set","position":[7424,1712],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{ $json.body}}"},"typeVersion":3.4},{"id":"1a9aa8de-b20f-4cac-9fde-9d889caee19e","name":"SET | Set New+Old Person (Selection)","type":"n8n-nodes-base.set","position":[7664,1712],"parameters":{"options":{},"assignments":{"assignments":[{"id":"e34ab1c9-3985-432b-9637-6a695fbf5931","name":"new","type":"string","value":"={{ $json.person }}"},{"id":"b3f6ce98-c6bc-4fea-a581-d1abcd087df4","name":"old","type":"string","value":"={{ $('LOOP | Iterate Persons').item.json.person_new }}"}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"205a6d3a-9108-4b8b-9698-5ba8db844f88","name":"MERGE | Combine Person Mapping Entries","type":"n8n-nodes-base.merge","position":[7920,1904],"parameters":{},"typeVersion":3.2},{"id":"eaee6930-3da6-40a9-ba0f-84ab8543b451","name":"MERGE | Loop Entry (Person)","type":"n8n-nodes-base.merge","position":[5696,2256],"parameters":{},"typeVersion":3.2},{"id":"e2241bb1-eae6-4311-909c-a67bb2bd52fe","name":"SET | Set Resolved Person","type":"n8n-nodes-base.set","position":[6208,2256],"parameters":{"options":{},"assignments":{"assignments":[{"id":"47a00b45-f580-4568-9913-b2359e1c1d8c","name":"person_new","type":"string","value":"={{ $json.replace ?? $('IF | Person Known?').item.json.person_new}}"}]}},"typeVersion":3.4},{"id":"9a37179d-2d3c-48e3-9ce1-1624b626b6fd","name":"MERGE | Combine Person Mapping","type":"n8n-nodes-base.merge","position":[6448,2048],"parameters":{},"typeVersion":3.2},{"id":"183d2e80-d18b-403e-a3f0-86d41fd0c0b1","name":"IF | Category or Person Callback?","type":"n8n-nodes-base.if","position":[2816,576],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"a6650d78-63a0-4bc4-ac46-e076eba14def","operator":{"type":"string","operation":"contains"},"leftValue":"{{json.message.text}}","rightValue":"Kategorie"}]}},"typeVersion":2.3},{"id":"0ac9e7b3-a794-4a42-b48b-1d42ba317bbc","name":"HTTP | Forward Person Selection","type":"n8n-nodes-base.httpRequest","position":[3312,688],"parameters":{"url":"={{ $json.resumeUrl }}","method":"POST","options":{},"jsonBody":"={\n  \"person\": \"{{ $json.person }}\"\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.3},{"id":"36db9da8-b32c-4b48-b7d4-6871eed49cb0","name":"TG | Confirm Person Selection","type":"n8n-nodes-base.telegram","position":[3504,688],"webhookId":"","parameters":{"text":"=Du hast \" {{ $('MSG | Telegram Inbound').item.json.callback_query.data }}\" ausgewählt\"","chatId":"={{ $('MSG | Telegram Inbound').item.json.callback_query.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"","name":"YOUR_TELEGRAM_CREDENTIAL"}},"typeVersion":1.2},{"id":"17fceb64-ac93-42b7-af34-fc5f1d0cb3d2","name":"JS | Read Person Callback","type":"n8n-nodes-base.code","position":[3104,688],"parameters":{"jsCode":"const callbackData = $json.callback_query.data;\nconst text = $json.callback_query.message.text;\nconst entities = $json.callback_query.message.entities;\n\n// URL aus den message entities auslesen\nconst urlEntity = entities.find(e => e.type === 'text_link');\nconst resumeUrl = urlEntity.url;\n\nreturn [{\n  json: {\n    person: callbackData,\n    resumeUrl: resumeUrl\n  }\n}];"},"typeVersion":2},{"id":"a742d127-062b-4f7d-8c4d-0b089439508e","name":"JS | Merge Intent Fields","type":"n8n-nodes-base.code","position":[9168,1264],"parameters":{"jsCode":"const items = $input.all();\n\nconst result = {};\n\nfor (const item of items) {\n  for (const [key, value] of Object.entries(item.json)) {\n    if (\n      value !== undefined &&\n      value !== null &&\n      value !== \"\" &&\n      value !== \"undefined\"\n    ) {\n      result[key] = value;\n    }\n  }\n}\n\nreturn [{\n  json: result,\n  pairedItem: { item: 0 }\n}];"},"typeVersion":2},{"id":"f4353b36-c5f3-4e13-baf8-a257e81fbf43","name":"StickyNote_Layer1","type":"n8n-nodes-base.stickyNote","position":[1968,0],"parameters":{"color":5,"width":1740,"height":1288,"content":"## 🟢 LAYER 1 — INPUT\nReceives incoming Telegram messages & callbacks.\nAuthorizes users and routes by message type.\n\n---\n\n⚙️ **ACTION REQUIRED**\n\n**1. Connect Telegram Credential**\nOpen the `MSG | Telegram Inbound` node and connect your Telegram Bot credential.\nDo the same for all other `TG |` nodes in this layer.\n→ *Nodes: MSG | Telegram Inbound, TG | Confirm Category Selection, TG | Confirm Person Selection*\n\n**2. Add authorized Chat IDs**\nOpen `IF | User Authorized?` and replace the placeholder values (`1000000000`, `1000000001`) with the real Telegram Chat IDs of all users who should have access.\nEach person can find their Chat ID by messaging @userinfobot on Telegram.\n"},"typeVersion":1},{"id":"b6684ba8-b5ab-41fe-8c1c-9ec20255983d","name":"StickyNote_Layer2","type":"n8n-nodes-base.stickyNote","position":[1968,1312],"parameters":{"width":1730,"height":1284,"content":"## 🔵 LAYER 2 — INTENT PARSING\n\n---\n\n⚙️ **ACTION REQUIRED**\n\n**1. Connect OpenAI Credential**\nOpen the `LLM | Parse Intent` node and connect your OpenAI API credential."},"typeVersion":1},{"id":"c6ddda36-1b63-428b-932d-2d9c857aa12d","name":"StickyNote_Layer3","type":"n8n-nodes-base.stickyNote","position":[3712,0],"parameters":{"color":3,"width":4970,"height":1296,"content":"## 🟡 LAYER 3a — ENTITY RESOLUTION: CATEGORIES\nResolves raw category strings to canonical names via mapping sheets.\nUnknown entities → LLM classification → user confirmation → alias saved.\n\n---\n\n⚙️ **ACTION REQUIRED**\n\n**1. Connect your `categories_mapping` Google Sheet**\nOpen `GS | Read Category Mapping` and `GS | Save Category Mapping`.\nReplace `YOUR_SPREADSHEET_ID` with the ID of your `categories_mapping` sheet.\nRequired columns: `find` · `replace`\n\n**2. Connect your `expense_categories` Google Sheet**\nOpen `GS | Read Allowed Categories`.\nReplace `YOUR_SPREADSHEET_ID` with the ID of your `expense_categories` sheet.\nRequired columns: `category` · `description` · `examples`\n\n**3. Connect OpenAI Credential**\nOpen `LLM | Classify Category` and connect your OpenAI API credential.\n\n**4. Connect Telegram Credential**\nOpen `TG | Confirm Category Suggestion` and connect your Telegram Bot credential.\n\n**5. Set your Bot Token in HTTP nodes**\nOpen `HTTP | Send Category Selection Message`.\nReplace `{{YOUR_BOT_TOKEN}}` in the URL with your actual Telegram Bot Token."},"typeVersion":1},{"id":"90172522-bfdb-4fa7-8ef3-48c2ee914994","name":"StickyNote_Layer4","type":"n8n-nodes-base.stickyNote","position":[8688,0],"parameters":{"color":4,"width":1712,"height":2592,"content":"## 🟠 LAYER 4 — QUERY ENGINE\nLoads expense data from Google Sheets.\nMerges resolved intent with raw data for filtering.\n\n---\n\n⚙️ **ACTION REQUIRED**\n\n**1. Connect your `expenses` Google Sheet**\nOpen `GS | Load Expenses` and replace `YOUR_SPREADSHEET_ID` with your expenses sheet ID.\nRequired columns: `date` · `amount` · `category` · `description` · `common_expense` · `Person`\n\n**2. Connect your `expense_categories` Google Sheet**\nOpen `GS | Load Categories` and replace `YOUR_SPREADSHEET_ID` with your categories sheet ID.\nRequired columns: `category` · `description` · `examples`"},"typeVersion":1},{"id":"4e94aa93-bca3-4087-b52c-de55b3f7be23","name":"StickyNote_Layer5","type":"n8n-nodes-base.stickyNote","position":[10400,0],"parameters":{"color":2,"width":564,"height":2592,"content":"## 🔴 LAYER 5 — ANALYTICS & AGGREGATION\nApplies date, person, category and common_only filters.\nComputes totals, category breakdown and person breakdown.\n\n---\n\n⚙️ **ACTION REQUIRED**\n\nNo setup required for this layer.\nThe `JS | Filter & Aggregate` node works automatically based on the resolved intent from the previous layers.\nIf you add custom columns to your expenses sheet, update the filter logic in this node accordingly."},"typeVersion":1},{"id":"a566ae23-972c-4c15-aa4d-b2ea0e14c8f4","name":"StickyNote_Layer6","type":"n8n-nodes-base.stickyNote","position":[10976,0],"parameters":{"color":6,"width":560,"height":2592,"content":"## 🟣 LAYER 6 — RESPONSE\nFormats the final message and sends it back via Telegram.\n\n---\n\n⚙️ **ACTION REQUIRED**\n\n**1. Connect Telegram Credential**\nOpen `TG | Send Reply` and connect your Telegram Bot credential.\n\n**2. Adjust the message format (optional)**\nOpen `JS | Format Response Message` to customise the output format, currency symbol, or language of the reply message."},"typeVersion":1},{"id":"ed4de5df-0c7f-49e6-9580-9bcec3a29756","name":"StickyNote_Layer","type":"n8n-nodes-base.stickyNote","position":[3712,1296],"parameters":{"color":6,"width":4970,"height":1296,"content":"## 🟡 LAYER 3b — ENTITY RESOLUTION: PERSONS\n\n\n---\n\n⚙️ **ACTION REQUIRED**\n\n**1. Connect your `person_mapping` Google Sheet**\nOpen `GS | Read Person Mapping` and `GS | Save Person Mapping`.\nReplace `YOUR_SPREADSHEET_ID` with the ID of your `person_mapping` sheet.\nRequired columns: `find` · `replace`\n\n**2. Connect your `list_persons` sheet**\nOpen `GS | Read Allowed Persons`.\nThis reads from the `list_persons` tab of the same `person_mapping` spreadsheet.\nRequired column: `person`\n\n**3. Connect OpenAI Credential**\nOpen `LLM | Classify Person` and connect your OpenAI API credential.\n\n**4. Connect Telegram Credential**\nOpen `TG | Confirm Person Suggestion` and connect your Telegram Bot credential.\n\n**5. Set your Bot Token in HTTP nodes**\nOpen `HTTP | Send Person Selection Message`.\nReplace `{{YOUR_BOT_TOKEN}}` in the URL with your actual Telegram Bot Token."},"typeVersion":1},{"id":"453a9f82-a297-4fb6-adc1-08f2e5619986","name":"DOC | Layer 1 — Input","type":"n8n-nodes-base.stickyNote","position":[1968,464],"parameters":{"color":5,"width":540,"height":500,"content":"\n\n**Purpose:** Entry point of the workflow. Receives all incoming Telegram events and routes them to the correct processing path.\n\n**What happens here:**\n- `MSG | Telegram Inbound` — Listens for incoming Telegram messages and callback queries (inline button taps).\n- `IF | Message or Callback?` — Splits the flow: regular text messages go to intent parsing, callback queries (button responses) are handled separately.\n- `IF | User Authorized?` — Checks whether the sender's chat ID is on the allowlist. Unauthorized users are silently dropped.\n- `IF | Category or Person Callback?` — Determines whether an incoming callback is a category or person selection and routes accordingly.\n- `JS | Read Category Callback` / `JS | Read Person Callback` — Extracts the selected value and the resume URL from the callback payload.\n- `HTTP | Forward Category/Person Selection` — Resumes the waiting workflow branch by POSTing the selected value to the internal webhook.\n- `TG | Confirm Category/Person Selection` — Sends a short confirmation message to the user acknowledging their selection."},"typeVersion":1},{"id":"a1283c4a-bad8-4116-a97c-0d2bbaa0f5ef","name":"DOC | Layer 2 — Intent Parsing","type":"n8n-nodes-base.stickyNote","position":[1984,1664],"parameters":{"width":412,"height":392,"content":"\n**Purpose:** Converts the user's free-text message into a structured JSON object that all downstream layers can work with.\n\n**What happens here:**\n- `LLM | Parse Intent` — Sends the raw message to GPT-4.1-nano with a strict system prompt. Returns a JSON object containing: intent, time_reference, explicit dates, person, category, common_only flag, comparison type and group_by dimension.\n- `JS | Extract Intent JSON` — Cleans the raw LLM response (strips markdown fences if present) and parses it into a proper JSON node output. Falls back to a safe empty-intent object if parsing fails."},"typeVersion":1},{"id":"f593b6d4-1dce-475b-928d-7c9850bda508","name":"DOC | Layer 3a — Entity Resolution: Categories","type":"n8n-nodes-base.stickyNote","position":[4384,128],"parameters":{"color":3,"width":540,"height":644,"content":"\n\n**Purpose:** Resolves raw category strings from the intent into valid canonical category names as defined in the categories master sheet.\n\n**What happens here:**\n- `IF | Category Present?` — Skips the entire branch if no category was mentioned.\n- `SPLIT | Split Categories` — Splits multi-category intents into individual items for per-item processing.\n- `GS | Read Category Mapping` — Loads the alias→canonical mapping sheet (e.g. \"essen\" → \"food\").\n- `MERGE | Join Categories with Mapping` + `SET | Normalize Category` — Applies alias replacement where available, keeps original otherwise.\n- `GS | Read Allowed Categories` + `MERGE | Check Category against Allowed` — Validates the normalised category against the master list.\n- `IF | Category Known?` — Known categories pass through directly; unknown ones enter the LLM resolution loop.\n- `LOOP | Iterate Categories` — Processes unresolved categories one by one.\n- `LLM | Classify Category` — GPT maps the unknown input to the closest canonical category from the allowed list.\n- `TG | Confirm Category Suggestion` — Sends the LLM suggestion to the user as a Yes/No confirmation.\n- `IF | Category Suggestion Accepted?` — On confirmation the mapping is saved; otherwise an inline-button picker is shown (`JS | Build Category Inline Buttons` → `HTTP | Send Category Selection Message` → `WAIT | Wait for Category Selection`).\n- `GS | Save Category Mapping` — Persists the newly learned alias for future queries."},"typeVersion":1},{"id":"1b9d5cb8-c8b9-4afd-919f-ef51ffbd2109","name":"DOC | Layer 3b — Entity Resolution: Persons","type":"n8n-nodes-base.stickyNote","position":[4448,1376],"parameters":{"color":6,"width":572,"height":556,"content":"**Purpose:** Mirrors Layer 3a but for person names — resolves nicknames and unknown names to canonical person records.\n\n**What happens here:**\n- `IF | Person Present?` — Skips the branch entirely when no person was specified.\n- `SPLIT | Split Persons` — Splits the person field into individual items.\n- `GS | Read Person Mapping` — Loads the alias→canonical person mapping (e.g. \"nickname\" → \"Full Name\").\n- `MERGE | Join Persons with Mapping` + `SET | Normalize Person` — Applies alias replacement where available.\n- `GS | Read Allowed Persons` + `MERGE | Check Person against Allowed` — Validates the resolved name against the known persons list.\n- `IF | Person Known?` — Known persons pass through; unknown ones enter the LLM resolution loop.\n- `LOOP | Iterate Persons` — Processes unresolved person names one at a time.\n- `LLM | Classify Person` — GPT maps the unknown name to the nearest known person from the allowed list.\n- `TG | Confirm Person Suggestion` — Asks the user to confirm the suggestion via Yes/No button.\n- `IF | Person Suggestion Accepted?` — On confirmation the mapping is saved; otherwise a button picker is shown (`JS | Build Person Inline Buttons` → `HTTP | Send Person Selection Message` → `WAIT | Wait for Person Selection`).\n- `GS | Save Person Mapping` — Stores the new alias for future use."},"typeVersion":1},{"id":"c7f0bb66-e951-4962-ac01-999e805c887c","name":"DOC | Layer 4 — Query Engine","type":"n8n-nodes-base.stickyNote","position":[8704,416],"parameters":{"color":4,"width":524,"height":428,"content":"\n**Purpose:** Assembles the fully resolved intent and loads raw expense data from Google Sheets, ready for filtering.\n\n**What happens here:**\n- `SET | Assemble Resolved Intent` — Merges canonical category and person values back into the original intent object, producing one clean query descriptor.\n- `GS | Load Expenses` — Reads all rows from the expenses Google Sheet (date, amount, category, person, common_expense flag).\n- `GS | Load Categories` — Loads the categories reference sheet in parallel (used for validation during filtering).\n- `MERGE | Combine Expenses + Categories` — Combines both data sources into a single output so the next layer has everything it needs."},"typeVersion":1},{"id":"4f17b844-0e95-469e-a6b3-b33edf5b96f7","name":"DOC | Layer 5 — Analytics & Aggregation","type":"n8n-nodes-base.stickyNote","position":[10448,480],"parameters":{"color":2,"width":348,"height":340,"content":"\n**Purpose:** Applies all filters from the resolved intent to the expense data and computes the requested aggregations.\n\n**What happens here:**\n- `JS | Filter & Aggregate` — Single code node that does everything: resolves relative date references (this_week, last_month, …) into concrete ranges, applies person / category / common_only filters row by row, then computes total amount, transaction count, and optional breakdowns by category or person (driven by the group_by field in the intent)."},"typeVersion":1},{"id":"6d8d1b8c-93db-4374-9240-b01174d354d5","name":"DOC | Layer 6 — Response","type":"n8n-nodes-base.stickyNote","position":[11008,128],"parameters":{"color":6,"width":460,"height":308,"content":"**Purpose:** Formats the aggregation result into a human-readable Telegram message and delivers it back to the user.\n\n**What happens here:**\n- `JS | Format Response Message` — Builds the final message string: period header, applied filters, total amount, transaction count, and — if requested — a sorted category or person breakdown with percentage shares. Handles the empty-result case gracefully.\n- `TG | Send Reply` — Sends the formatted message as a Markdown reply to the original chat, referencing the triggering message ID so it appears as a thread reply."},"typeVersion":1},{"id":"9c55a9fc-45aa-4ac4-a94f-7736abee4e73","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[1008,0],"parameters":{"color":7,"width":912,"height":2576,"content":"# 🔄 WORKFLOW OVERVIEW\n\n## 🟩 Input & Security (Layer 1)\n\nEvery incoming Telegram message or button tap is received by the trigger.\n\nThe workflow checks whether the sender's **Chat ID** is on the approved list — unauthorized users are silently ignored.\n\nCallback responses (inline button taps for category or person disambiguation) are also handled here and routed back into the correct waiting branch.\n\n---\n\n## 🟦 Intent Parsing (Layer 2)\n\nThe raw message is sent to **GPT-4.1-nano** with a strict system prompt.\n\nThe model returns a structured JSON object containing:\n\n- `intent`\n- `time_reference`\n- `explicit_date_range`\n- `person`\n- `category`\n- `common_only`\n- `comparison_type`\n- `group_by`\n\nA fallback **Code Node** cleans the response and handles parsing errors gracefully.\n\n---\n\n## 🟨 Entity Resolution\n\n### Layer 3a — Categories  \n### Layer 3b — Persons\n\nRaw category strings and person names from the intent are resolved to canonical values using **Google Sheets mapping tables**.\n\nIf a value is unknown:\n\n1. GPT classifies it against the allowed list  \n2. The user is asked to confirm via a **Yes/No Telegram button**\n\nIf the user rejects the suggestion, an **inline button picker** is shown instead.\n\nEvery confirmed match is saved back to the mapping sheet so future queries resolve automatically.\n\n**The system learns over time.**\n\n---\n\n## 🟧 Query Engine (Layer 4)\n\nThe fully resolved intent is assembled into one clean **query descriptor**.\n\nAll expense rows and the category reference list are loaded from **Google Sheets in parallel** and merged into a single data object.\n\n---\n\n## 🟥 Analytics & Aggregation (Layer 5)\n\nA single **Code Node** applies all filters:\n\n- date range  \n- relative time references (last month, this week, etc.)  \n- person  \n- category  \n- `common_only` flag  \n\nIt then computes:\n\n- **total amount**\n- **transaction count**\n- optional **breakdowns**\n\nBreakdowns are calculated depending on the `group_by` field:\n\n- by **category**\n- by **person**\n\n---\n\n## 🟪 Response (Layer 6)\n\nThe result is formatted into a clean **Markdown message** including:\n\n- period  \n- applied filters  \n- total  \n- count  \n- optional breakdowns with percentage shares  \n\nThe reply is sent directly back to the user's **Telegram chat** as a thread reply to the original message."},"typeVersion":1},{"id":"14b52ff0-e0db-42be-8f44-066315ba7642","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-16,0],"parameters":{"color":7,"width":1024,"height":2576,"content":"# HOW IT WORKS — AI TELEGRAM EXPENSE TRACKER (QUERY MODE)\n\nThis workflow answers natural language expense questions from Telegram using AI.\n\nInstead of opening spreadsheets, simply send a message like:\n\n- *How much did I spend on food last month?*\n- *What did we spend together this week?*\n- *Show me a breakdown by category for January.*\n\nThe workflow understands your question, resolves ambiguous names or categories, queries your expense data, and replies with a formatted summary — automatically.\n\n\n\n# 📋 WHAT YOU NEED\n\nFour **Google Sheets** are required before using this workflow.\n\n## 📋 WHAT YOU NEED\n\nFive Google Sheets are required before using this workflow.\n\n---\n\n**expenses**\n\nColumns:\n- date (date of expense)\n- amount (amount of expense)\n- category (expense category - e.g. supermarket)\n- description (description of the expense)\n- common_expense (true if it was an expense for all people - e.g. in a household)\n- Person - (Who made the expense)\n\nPurpose:\nMain expense table containing all recorded transactions.\n\n---\n\n**expense_categories**\n\nColumns:\n- category\n- description\n- examples\n\nPurpose:\nReference list of allowed expense categories used for classification.\n\n---\n\n**categories_mapping**\n\nColumns:\n- find\n- replace\n\nPurpose:\nMaps user aliases to canonical categories.\n\nExample:\n- sushi → food\n\n---\n\n**person_mapping**\n\nColumns:\n- find\n- replace\n\nPurpose:\nMaps nicknames or aliases to canonical person names.\n\nExample:\n- Johnny -> John\n\n---\n\n**list_persons**\n\nColumns:\n- person\n- description\n\nPurpose:\nReference list of all persons that can appear in the expense data.\n\n---\n\n# 💡 KEY FEATURES\n\n- Natural language queries in **German & English**\n- AI-powered intent parsing with **GPT-4.1-nano**\n- **Self-learning category & person resolution system**\n- Interactive disambiguation via **Telegram inline buttons**\n- Relative date support: this week, last month, this year\n- Group-by breakdowns: by category or by person\n- `common_only` filter for shared expense queries\n\n---\n\n# ⭐ MULTI-USER SETUP\n\nThis workflow supports **multiple users simultaneously**.\n\nAdd all approved **Chat IDs** in the node:\n\nIF | User Authorized?\n\nEach expense query is automatically scoped to the sender unless:\n\n- a specific **person** is mentioned\n- or **\"we\"** is used.\n\nShared expenses are identified by the column:\n\ncommon_expense (boolean true / false)\n\nQueries like:\n\n*\"what did we spend together?\"*\n\nautomatically filter for **shared entries only**."},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"","connections":{"GS | Load Expenses":{"main":[[{"node":"MERGE | Combine Expenses + Categories","type":"main","index":0}]]},"IF | Person Known?":{"main":[[{"node":"MERGE | Combine Persons with List","type":"main","index":0}],[{"node":"MERGE | Loop Entry (Person)","type":"main","index":1}]]},"LLM | Parse Intent":{"main":[[{"node":"JS | Extract Intent JSON","type":"main","index":0}]]},"GS | Load Categories":{"main":[[{"node":"MERGE | Combine Expenses + Categories","type":"main","index":1}]]},"IF | Category Known?":{"main":[[{"node":"MERGE | Combine Categories with List","type":"main","index":0}],[{"node":"MERGE | Loop Entry (Category)","type":"main","index":1}]]},"IF | Person Present?":{"main":[[{"node":"MERGE | Combine Person Mapping","type":"main","index":0}],[{"node":"SPLIT | Split Persons","type":"main","index":0},{"node":"GS | Read Person Mapping","type":"main","index":0},{"node":"GS | Read Allowed Persons","type":"main","index":0}]]},"IF | User Authorized?":{"main":[[{"node":"LLM | Parse Intent","type":"main","index":0}]]},"LLM | Classify Person":{"main":[[{"node":"SET | Extract LLM Person","type":"main","index":0}]]},"SPLIT | Split Persons":{"main":[[{"node":"MERGE | Join Persons with Mapping","type":"main","index":0}]]},"IF | Category Present?":{"main":[[{"node":"MERGE | Combine Category + Person","type":"main","index":0}],[{"node":"SPLIT | Split Categories","type":"main","index":0},{"node":"GS | Read Category Mapping","type":"main","index":0},{"node":"GS | Read Allowed Categories","type":"main","index":0}]]},"LOOP | Iterate Persons":{"main":[[{"node":"MERGE | Loop Entry (Person)","type":"main","index":0}],[{"node":"LLM | Classify Person","type":"main","index":0}]]},"MSG | Telegram Inbound":{"main":[[{"node":"IF | Message or Callback?","type":"main","index":0}]]},"SET | Normalize Person":{"main":[[{"node":"MERGE | Check Person against Allowed","type":"main","index":0}]]},"JS | Filter & Aggregate":{"main":[[{"node":"JS | Format Response Message","type":"main","index":0}]]},"LLM | Classify Category":{"main":[[{"node":"SET | Extract LLM Category","type":"main","index":0}]]},"GS | Read Person Mapping":{"main":[[{"node":"MERGE | Join Persons with Mapping","type":"main","index":1}]]},"GS | Save Person Mapping":{"main":[[{"node":"LOOP | Iterate Persons","type":"main","index":0}]]},"JS | Extract Intent JSON":{"main":[[{"node":"IF | Category Present?","type":"main","index":0},{"node":"IF | Person Present?","type":"main","index":0}]]},"JS | Merge Intent Fields":{"main":[[{"node":"SET | Assemble Resolved Intent","type":"main","index":0}]]},"SET | Extract LLM Person":{"main":[[{"node":"TG | Confirm Person Suggestion","type":"main","index":0}]]},"SET | Normalize Category":{"main":[[{"node":"MERGE | Check Category against Allowed","type":"main","index":0}]]},"SPLIT | Split Categories":{"main":[[{"node":"MERGE | Join Categories with Mapping","type":"main","index":0}]]},"GS | Read Allowed Persons":{"main":[[{"node":"MERGE | Check Person against Allowed","type":"main","index":1},{"node":"AGG | Aggregate Person List","type":"main","index":0}]]},"IF | Message or Callback?":{"main":[[{"node":"IF | User Authorized?","type":"main","index":0}],[{"node":"IF | Category or Person Callback?","type":"main","index":0}]]},"JS | Read Person Callback":{"main":[[{"node":"HTTP | Forward Person Selection","type":"main","index":0}]]},"LOOP | Iterate Categories":{"main":[[{"node":"MERGE | Loop Entry (Category)","type":"main","index":0}],[{"node":"LLM | Classify Category","type":"main","index":0}]]},"SET | Set Resolved Person":{"main":[[{"node":"MERGE | Combine Person Mapping","type":"main","index":1}]]},"GS | Read Category Mapping":{"main":[[{"node":"MERGE | Join Categories with Mapping","type":"main","index":1}]]},"GS | Save Category Mapping":{"main":[[{"node":"LOOP | Iterate Categories","type":"main","index":0}]]},"SET | Extract LLM Category":{"main":[[{"node":"TG | Confirm Category Suggestion","type":"main","index":0}]]},"AGG | Aggregate Person List":{"main":[[{"node":"MERGE | Combine Persons with List","type":"main","index":1}]]},"JS | Read Category Callback":{"main":[[{"node":"HTTP | Forward Category Selection","type":"main","index":0}]]},"MERGE | Loop Entry (Person)":{"main":[[{"node":"SET | Set Resolved Person","type":"main","index":0}]]},"SET | Set Resolved Category":{"main":[[{"node":"AGG | Aggregate Resolved Categories","type":"main","index":0}]]},"GS | Read Allowed Categories":{"main":[[{"node":"MERGE | Check Category against Allowed","type":"main","index":1},{"node":"AGG | Aggregate Category List","type":"main","index":0}]]},"JS | Format Response Message":{"main":[[{"node":"TG | Send Reply","type":"main","index":0}]]},"AGG | Aggregate Category List":{"main":[[{"node":"MERGE | Combine Categories with List","type":"main","index":1}]]},"MERGE | Loop Entry (Category)":{"main":[[{"node":"SET | Set Resolved Category","type":"main","index":0}]]},"MERGE | Combine Person Mapping":{"main":[[{"node":"MERGE | Combine Category + Person","type":"main","index":2}]]},"SET | Assemble Resolved Intent":{"main":[[{"node":"GS | Load Expenses","type":"main","index":0},{"node":"GS | Load Categories","type":"main","index":0}]]},"SET | Set New+Old Person (LLM)":{"main":[[{"node":"MERGE | Combine Person Mapping Entries","type":"main","index":1}]]},"TG | Confirm Person Suggestion":{"main":[[{"node":"IF | Person Suggestion Accepted?","type":"main","index":0}]]},"HTTP | Forward Person Selection":{"main":[[{"node":"TG | Confirm Person Selection","type":"main","index":0}]]},"SET | Read Callback Body (Cat.)":{"main":[[{"node":"SET | Set New+Old Category (Selection)","type":"main","index":0}]]},"IF | Person Suggestion Accepted?":{"main":[[{"node":"SET | Set New+Old Person (LLM)","type":"main","index":0}],[{"node":"JS | Build Person Inline Buttons","type":"main","index":0}]]},"JS | Build Person Inline Buttons":{"main":[[{"node":"HTTP | Send Person Selection Message","type":"main","index":0}]]},"SET | Set New+Old Category (LLM)":{"main":[[{"node":"MERGE | Combine Category Mapping Entries","type":"main","index":1}]]},"TG | Confirm Category Suggestion":{"main":[[{"node":"IF | Category Suggestion Accepted?","type":"main","index":0}]]},"WAIT | Wait for Person Selection":{"main":[[{"node":"SET | Read Callback Body (Person)","type":"main","index":0}]]},"HTTP | Forward Category Selection":{"main":[[{"node":"TG | Confirm Category Selection","type":"main","index":0}]]},"IF | Category or Person Callback?":{"main":[[{"node":"JS | Read Category Callback","type":"main","index":0}],[{"node":"JS | Read Person Callback","type":"main","index":0}]]},"MERGE | Combine Category + Person":{"main":[[{"node":"JS | Merge Intent Fields","type":"main","index":0}]]},"MERGE | Combine Persons with List":{"main":[[{"node":"LOOP | Iterate Persons","type":"main","index":0}]]},"MERGE | Join Persons with Mapping":{"main":[[{"node":"SET | Normalize Person","type":"main","index":0}]]},"SET | Read Callback Body (Person)":{"main":[[{"node":"SET | Set New+Old Person (Selection)","type":"main","index":0}]]},"IF | Category Suggestion Accepted?":{"main":[[{"node":"SET | Set New+Old Category (LLM)","type":"main","index":0}],[{"node":"JS | Build Category Inline Buttons","type":"main","index":0}]]},"JS | Build Category Inline Buttons":{"main":[[{"node":"HTTP | Send Category Selection Message","type":"main","index":0}]]},"WAIT | Wait for Category Selection":{"main":[[{"node":"SET | Read Callback Body (Cat.)","type":"main","index":0}]]},"AGG | Aggregate Resolved Categories":{"main":[[{"node":"MERGE | Combine Category + Person","type":"main","index":1}]]},"HTTP | Send Person Selection Message":{"main":[[{"node":"WAIT | Wait for Person Selection","type":"main","index":0}]]},"MERGE | Check Person against Allowed":{"main":[[{"node":"IF | Person Known?","type":"main","index":0}]]},"MERGE | Combine Categories with List":{"main":[[{"node":"LOOP | Iterate Categories","type":"main","index":0}]]},"MERGE | Join Categories with Mapping":{"main":[[{"node":"SET | Normalize Category","type":"main","index":0}]]},"SET | Set New+Old Person (Selection)":{"main":[[{"node":"MERGE | Combine Person Mapping Entries","type":"main","index":0}]]},"MERGE | Combine Expenses + Categories":{"main":[[{"node":"JS | Filter & Aggregate","type":"main","index":0}]]},"HTTP | Send Category Selection Message":{"main":[[{"node":"WAIT | Wait for Category Selection","type":"main","index":0}]]},"MERGE | Check Category against Allowed":{"main":[[{"node":"IF | Category Known?","type":"main","index":0}]]},"MERGE | Combine Person Mapping Entries":{"main":[[{"node":"GS | Save Person Mapping","type":"main","index":0}]]},"SET | Set New+Old Category (Selection)":{"main":[[{"node":"MERGE | Combine Category Mapping Entries","type":"main","index":0}]]},"MERGE | Combine Category Mapping Entries":{"main":[[{"node":"GS | Save Category Mapping","type":"main","index":0}]]}}},"lastUpdatedBy":1,"workflowInfo":{"nodeCount":89,"nodeTypes":{"n8n-nodes-base.if":{"count":9},"n8n-nodes-base.set":{"count":13},"n8n-nodes-base.code":{"count":8},"n8n-nodes-base.wait":{"count":2},"n8n-nodes-base.merge":{"count":13},"n8n-nodes-base.splitOut":{"count":2},"n8n-nodes-base.telegram":{"count":5},"n8n-nodes-base.aggregate":{"count":3},"n8n-nodes-base.stickyNote":{"count":16},"n8n-nodes-base.httpRequest":{"count":4},"n8n-nodes-base.googleSheets":{"count":8},"n8n-nodes-base.splitInBatches":{"count":2},"n8n-nodes-base.telegramTrigger":{"count":1},"@n8n/n8n-nodes-langchain.openAi":{"count":3}}},"status":"published","readyToDemo":null,"user":{"name":"Robin","username":"robinvm","bio":"I design automated data systems — from ingestion to insight.\nPython | dbt | n8n | Tableau | Data Quality","verified":false,"links":["https://medium.com/@robinvm"],"avatar":"https://gravatar.com/avatar/2ffa76cd23594a355e441c0b2144d28de99a292c4e382505d6d1df157aa1c7ce?r=pg&d=retro&size=200"},"nodes":[{"id":18,"icon":"file:googleSheets.svg","name":"n8n-nodes-base.googleSheets","codex":{"data":{"alias":["CSV","Sheet","Spreadsheet","GS"],"resources":{"generic":[{"url":"https://n8n.io/blog/love-at-first-sight-ricardos-n8n-journey/","icon":"❤️","label":"Love at first sight: Ricardo’s n8n journey"},{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/supercharging-your-conference-registration-process-with-n8n/","icon":"🎫","label":"Supercharging your conference registration process with n8n"},{"url":"https://n8n.io/blog/creating-triggers-for-n8n-workflows-using-polling/","icon":"⏲","label":"Creating triggers for n8n workflows using polling"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/migrating-community-metrics-to-orbit-using-n8n/","icon":"📈","label":"Migrating Community Metrics to Orbit using n8n"},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/your-business-doesnt-need-you-to-operate/","icon":" 🖥️","label":"Hey founders! Your business doesn't need you to operate"},{"url":"https://n8n.io/blog/how-honest-burgers-use-automation-to-save-100k-per-year/","icon":"🍔","label":"How Honest Burgers Use Automation to Save $100k per year"},{"url":"https://n8n.io/blog/how-a-digital-strategist-uses-n8n-for-online-marketing/","icon":"💻","label":"How a digital strategist uses n8n for online marketing"},{"url":"https://n8n.io/blog/why-this-product-manager-loves-workflow-automation-with-n8n/","icon":"🧠","label":"Why this Product Manager loves workflow automation with n8n"},{"url":"https://n8n.io/blog/sending-automated-congratulations-with-google-sheets-twilio-and-n8n/","icon":"🙌","label":"Sending Automated Congratulations with Google Sheets, Twilio, and n8n "},{"url":"https://n8n.io/blog/how-a-membership-development-manager-automates-his-work-and-investments/","icon":"📈","label":"How a Membership Development Manager automates his work and investments"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlesheets/"}],"credentialDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/credentials/google/oauth-single-service/"}]},"categories":["Data & Storage","Productivity"],"nodeVersion":"1.0","codexVersion":"1.0"}},"group":"[\"input\",\"output\"]","defaults":{"name":"Google Sheets"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MCIgaGVpZ2h0PSI2MCI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGZpbGw9IiMyOEI0NDYiIGQ9Ik0zNS42OSAxIDUyIDE3LjIyNXYzOS4wODdhMy42NyAzLjY3IDAgMCAxLTEuMDg0IDIuNjFBMy43IDMuNyAwIDAgMSA0OC4yOTMgNjBIMTIuNzA3YTMuNyAzLjcgMCAwIDEtMi42MjMtMS4wNzhBMy42NyAzLjY3IDAgMCAxIDkgNTYuMzEyVjQuNjg4YTMuNjcgMy42NyAwIDAgMSAxLjA4NC0yLjYxQTMuNyAzLjcgMCAwIDEgMTIuNzA3IDF6Ii8+PHBhdGggZmlsbD0iIzZBQ0U3QyIgZD0iTTM1LjY5IDEgNTIgMTcuMjI1SDM5LjM5N2MtMi4wNTQgMC0zLjcwNy0xLjgyOS0zLjcwNy0zLjg3MnoiLz48cGF0aCBmaWxsPSIjMjE5QjM4IiBkPSJNMzkuMjExIDE3LjIyNSA1MiAyMi40OHYtNS4yNTV6Ii8+PHBhdGggZmlsbD0iI0ZGRiIgZD0iTTIwLjEyIDMxLjk3NWMwLS44MTcuNjYyLTEuNDc1IDEuNDgzLTEuNDc1aDE3Ljc5NGMuODIxIDAgMS40ODIuNjU4IDEuNDgyIDEuNDc1djE1LjQ4N2MwIC44MTgtLjY2MSAxLjQ3NS0xLjQ4MiAxLjQ3NUgyMS42MDNhMS40NzYgMS40NzYgMCAwIDEtMS40ODItMS40NzRWMzEuOTc0em0yLjIyNSAxLjQ3NWg2LjY3MnYyLjIxMmgtNi42NzJ6bTAgNS4xNjJoNi42NzJ2Mi4yMTNoLTYuNjcyem0wIDUuMTYzaDYuNjcydjIuMjEyaC02LjY3MnptOS42MzgtMTAuMzI1aDYuNjcydjIuMjEyaC02LjY3MnptMCA1LjE2Mmg2LjY3MnYyLjIxM2gtNi42NzJ6bTAgNS4xNjNoNi42NzJ2Mi4yMTJoLTYuNjcyeiIvPjxwYXRoIGZpbGw9IiMyOEI0NDYiIGQ9Ik0zNC42OSAwIDUxIDE2LjIyNXYzOS4wODdhMy42NyAzLjY3IDAgMCAxLTEuMDg0IDIuNjFBMy43IDMuNyAwIDAgMSA0Ny4yOTMgNTlIMTEuNzA3YTMuNyAzLjcgMCAwIDEtMi42MjMtMS4wNzhBMy42NyAzLjY3IDAgMCAxIDggNTUuMzEyVjMuNjg4YTMuNjcgMy42NyAwIDAgMSAxLjA4NC0yLjYxQTMuNyAzLjcgMCAwIDEgMTEuNzA3IDB6Ii8+PHBhdGggZmlsbD0iIzZBQ0U3QyIgZD0iTTM0LjY5IDAgNTEgMTYuMjI1SDM4LjM5N2MtMi4wNTQgMC0zLjcwNy0xLjgyOS0zLjcwNy0zLjg3MnoiLz48cGF0aCBmaWxsPSIjMjE5QjM4IiBkPSJNMzguMjExIDE2LjIyNSA1MSAyMS40OHYtNS4yNTV6Ii8+PHBhdGggZmlsbD0iI0ZGRiIgZD0iTTE5LjEyIDMwLjk3NWMwLS44MTcuNjYyLTEuNDc1IDEuNDgzLTEuNDc1aDE3Ljc5NGMuODIxIDAgMS40ODIuNjU4IDEuNDgyIDEuNDc1djE1LjQ4N2MwIC44MTgtLjY2MSAxLjQ3NS0xLjQ4MiAxLjQ3NUgyMC42MDNhMS40NzYgMS40NzYgMCAwIDEtMS40ODItMS40NzRWMzAuOTc0em0yLjIyNSAxLjQ3NWg2LjY3MnYyLjIxMmgtNi42NzJ6bTAgNS4xNjJoNi42NzJ2Mi4yMTNoLTYuNjcyem0wIDUuMTYzaDYuNjcydjIuMjEyaC02LjY3MnptOS42MzgtMTAuMzI1aDYuNjcydjIuMjEyaC02LjY3MnptMCA1LjE2Mmg2LjY3MnYyLjIxM2gtNi42NzJ6bTAgNS4xNjNoNi42NzJ2Mi4yMTJoLTYuNjcyeiIvPjwvZz48L3N2Zz4="},"displayName":"Google Sheets","typeVersion":5,"nodeCategories":[{"id":3,"name":"Data & Storage"},{"id":4,"name":"Productivity"}]},{"id":19,"icon":"file:httprequest.svg","name":"n8n-nodes-base.httpRequest","codex":{"data":{"alias":["API","Request","URL","Build","cURL"],"resources":{"generic":[{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/automatically-pulling-and-visualizing-data-with-n8n/","icon":"📈","label":"Automatically pulling and visualizing data with n8n"},{"url":"https://n8n.io/blog/learn-how-to-automatically-cross-post-your-content-with-n8n/","icon":"✍️","label":"Learn how to automatically cross-post your content with n8n"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/running-n8n-on-ships-an-interview-with-maranics/","icon":"🛳","label":"Running n8n on ships: An interview with Maranics"},{"url":"https://n8n.io/blog/what-are-apis-how-to-use-them-with-no-code/","icon":" 🪢","label":"What are APIs and how to use them with no code"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/world-poetry-day-workflow/","icon":"📜","label":"Celebrating World Poetry Day with a daily poem in Telegram"},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/automate-designs-with-bannerbear-and-n8n/","icon":"🎨","label":"Automate Designs with Bannerbear and n8n"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/building-an-expense-tracking-app-in-10-minutes/","icon":"📱","label":"Building an expense tracking app in 10 minutes"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/how-to-use-the-http-request-node-the-swiss-army-knife-for-workflow-automation/","icon":"🧰","label":"How to use the HTTP Request Node - The Swiss Army Knife for Workflow Automation"},{"url":"https://n8n.io/blog/learn-how-to-use-webhooks-with-mattermost-slash-commands/","icon":"🦄","label":"Learn how to use webhooks with Mattermost slash commands"},{"url":"https://n8n.io/blog/how-a-membership-development-manager-automates-his-work-and-investments/","icon":"📈","label":"How a Membership Development Manager automates his work and investments"},{"url":"https://n8n.io/blog/a-low-code-bitcoin-ticker-built-with-questdb-and-n8n-io/","icon":"📈","label":"A low-code bitcoin ticker built with QuestDB and n8n.io"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/automations-for-activists/","icon":"✨","label":"How Common Knowledge use workflow automation for activism"},{"url":"https://n8n.io/blog/creating-scheduled-text-affirmations-with-n8n/","icon":"🤟","label":"Creating scheduled text affirmations with n8n"},{"url":"https://n8n.io/blog/how-goomer-automated-their-operations-with-over-200-n8n-workflows/","icon":"🛵","label":"How Goomer automated their operations with over 200 n8n workflows"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/"}]},"categories":["Development","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"output\"]","defaults":{"name":"HTTP Request","color":"#0004F5"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00MCAyMEM0MCA4Ljk1MzE0IDMxLjA0NjkgMCAyMCAwQzguOTUzMTQgMCAwIDguOTUzMTQgMCAyMEMwIDMxLjA0NjkgOC45NTMxNCA0MCAyMCA0MEMzMS4wNDY5IDQwIDQwIDMxLjA0NjkgNDAgMjBaTTIwIDM2Ljk0NThDMTguODg1MiAzNi45NDU4IDE3LjEzNzggMzUuOTY3IDE1LjQ5OTggMzIuNjk4NUMxNC43OTY0IDMxLjI5MTggMTQuMTk2MSAyOS41NDMxIDEzLjc1MjYgMjcuNjg0N0gyNi4xODk4QzI1LjgwNDUgMjkuNTQwMyAyNS4yMDQ0IDMxLjI5MDEgMjQuNTAwMiAzMi42OTg1QzIyLjg2MjIgMzUuOTY3IDIxLjExNDggMzYuOTQ1OCAyMCAzNi45NDU4Wk0xMi45MDY0IDIwQzEyLjkwNjQgMjEuNjA5NyAxMy4wMDg3IDIzLjE2NCAxMy4yMDAzIDI0LjYzMDVIMjYuNzk5N0MyNi45OTEzIDIzLjE2NCAyNy4wOTM2IDIxLjYwOTcgMjcuMDkzNiAyMEMyNy4wOTM2IDE4LjM5MDMgMjYuOTkxMyAxNi44MzYgMjYuNzk5NyAxNS4zNjk1SDEzLjIwMDNDMTMuMDA4NyAxNi44MzYgMTIuOTA2NCAxOC4zOTAzIDEyLjkwNjQgMjBaTTIwIDMuMDU0MTlDMjEuMTE0OSAzLjA1NDE5IDIyLjg2MjIgNC4wMzA3OCAyNC41MDAxIDcuMzAwMzlDMjUuMjA2NiA4LjcxNDA4IDI1LjgwNzIgMTAuNDA2NyAyNi4xOTIgMTIuMzE1M0gxMy43NTAxQzE0LjE5MzMgMTAuNDA0NyAxNC43OTQyIDguNzEyNTQgMTUuNDk5OCA3LjMwMDY0QzE3LjEzNzcgNC4wMzA4MyAxOC44ODUxIDMuMDU0MTkgMjAgMy4wNTQxOVpNMzAuMTQ3OCAyMEMzMC4xNDc4IDE4LjQwOTkgMzAuMDU0MyAxNi44NjE3IDI5LjgyMjcgMTUuMzY5NUgzNi4zMDQyQzM2LjcyNTIgMTYuODQyIDM2Ljk0NTggMTguMzk2NCAzNi45NDU4IDIwQzM2Ljk0NTggMjEuNjAzNiAzNi43MjUyIDIzLjE1OCAzNi4zMDQyIDI0LjYzMDVIMjkuODIyN0MzMC4wNTQzIDIzLjEzODMgMzAuMTQ3OCAyMS41OTAxIDMwLjE0NzggMjBaTTI2LjI3NjcgNC4yNTUxMkMyNy42MzY1IDYuMzYwMTkgMjguNzExIDkuMTMyIDI5LjM3NzQgMTIuMzE1M0gzNS4xMDQ2QzMzLjI1MTEgOC42NjggMzAuMTA3IDUuNzgzNDYgMjYuMjc2NyA0LjI1NTEyWk0xMC42MjI2IDEyLjMxNTNINC44OTI5M0M2Ljc1MTQ3IDguNjY3ODQgOS44OTM1MSA1Ljc4MzQxIDEzLjcyMzIgNC4yNTUxM0MxMi4zNjM1IDYuMzYwMjEgMTEuMjg5IDkuMTMyMDEgMTAuNjIyNiAxMi4zMTUzWk0zLjA1NDE5IDIwQzMuMDU0MTkgMjEuNjAzIDMuMjc3NDMgMjMuMTU3NSAzLjY5NDg0IDI0LjYzMDVIMTAuMTIxN0M5Ljk0NjE5IDIzLjE0MiA5Ljg1MjIyIDIxLjU5NDMgOS44NTIyMiAyMEM5Ljg1MjIyIDE4LjQwNTcgOS45NDYxOSAxNi44NTggMTAuMTIxNyAxNS4zNjk1SDMuNjk0ODRDMy4yNzc0MyAxNi44NDI1IDMuMDU0MTkgMTguMzk3IDMuMDU0MTkgMjBaTTI2LjI3NjYgMzUuNzQyN0MyNy42MzY1IDMzLjYzOTMgMjguNzExIDMwLjg2OCAyOS4zNzc0IDI3LjY4NDdIMzUuMTA0NkMzMy4yNTEgMzEuMzMyMiAzMC4xMDY4IDM0LjIxNzkgMjYuMjc2NiAzNS43NDI3Wk0xMy43MjM0IDM1Ljc0MjdDOS44OTM2OSAzNC4yMTc5IDYuNzUxNTUgMzEuMzMyNCA0Ljg5MjkzIDI3LjY4NDdIMTAuNjIyNkMxMS4yODkgMzAuODY4IDEyLjM2MzUgMzMuNjM5MyAxMy43MjM0IDM1Ljc0MjdaIiBmaWxsPSIjM0E0MkU5Ii8+Cjwvc3ZnPgo="},"displayName":"HTTP Request","typeVersion":4,"nodeCategories":[{"id":5,"name":"Development"},{"id":9,"name":"Core Nodes"}]},{"id":20,"icon":"fa:map-signs","name":"n8n-nodes-base.if","codex":{"data":{"alias":["Router","Filter","Condition","Logic","Boolean","Branch"],"details":"The IF node can be used to implement binary conditional logic in your workflow. You can set up one-to-many conditions to evaluate each item of data being inputted into the node. That data will either evaluate to TRUE or FALSE and route out of the node accordingly.\n\nThis node has multiple types of conditions: Bool, String, Number, and Date & Time.","resources":{"generic":[{"url":"https://n8n.io/blog/learn-to-automate-your-factorys-incident-reporting-a-step-by-step-guide/","icon":"🏭","label":"Learn to Automate Your Factory's Incident Reporting: A Step by Step Guide"},{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/how-to-build-a-low-code-self-hosted-url-shortener/","icon":"🔗","label":"How to build a low-code, self-hosted URL shortener in 3 steps"},{"url":"https://n8n.io/blog/automate-your-data-processing-pipeline-in-9-steps-with-n8n/","icon":"⚙️","label":"Automate your data processing pipeline in 9 steps"},{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/automation-for-maintainers-of-open-source-projects/","icon":"🏷️","label":"How to automatically manage contributions to open-source projects"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/why-this-product-manager-loves-workflow-automation-with-n8n/","icon":"🧠","label":"Why this Product Manager loves workflow automation with n8n"},{"url":"https://n8n.io/blog/sending-automated-congratulations-with-google-sheets-twilio-and-n8n/","icon":"🙌","label":"Sending Automated Congratulations with Google Sheets, Twilio, and n8n "},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/benefits-of-automation-and-n8n-an-interview-with-hubspots-hugh-durkin/","icon":"🎖","label":"Benefits of automation and n8n: An interview with HubSpot's Hugh Durkin"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.if/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Flow"]}}},"group":"[\"transform\"]","defaults":{"name":"If","color":"#408000"},"iconData":{"icon":"map-signs","type":"icon"},"displayName":"If","typeVersion":2,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":24,"icon":"file:merge.svg","name":"n8n-nodes-base.merge","codex":{"data":{"alias":["Join","Concatenate","Wait"],"resources":{"generic":[{"url":"https://n8n.io/blog/how-to-sync-data-between-two-systems/","icon":"🏬","label":"How to synchronize data between two systems (one-way vs. two-way sync"},{"url":"https://n8n.io/blog/supercharging-your-conference-registration-process-with-n8n/","icon":"🎫","label":"Supercharging your conference registration process with n8n"},{"url":"https://n8n.io/blog/migrating-community-metrics-to-orbit-using-n8n/","icon":"📈","label":"Migrating Community Metrics to Orbit using n8n"},{"url":"https://n8n.io/blog/build-your-own-virtual-assistant-with-n8n-a-step-by-step-guide/","icon":"👦","label":"Build your own virtual assistant with n8n: A step by step guide"},{"url":"https://n8n.io/blog/sending-automated-congratulations-with-google-sheets-twilio-and-n8n/","icon":"🙌","label":"Sending Automated Congratulations with Google Sheets, Twilio, and n8n "},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.merge/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Flow","Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Merge"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xMTc3XzUxOCkiPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTAgNDhDMCAyMS40OTAzIDIxLjQ5MDMgMCA0OCAwSDExMkMxMzguNTEgMCAxNjAgMjEuNDkwMyAxNjAgNDhWNTZIMTk2LjI1MkMyNDAuNDM1IDU2IDI3Ni4yNTIgOTEuODE3MiAyNzYuMjUyIDEzNlYxOTJDMjc2LjI1MiAyMTQuMDkxIDI5NC4xNjEgMjMyIDMxNi4yNTIgMjMySDM1MlYyMjRDMzUyIDE5Ny40OSAzNzMuNDkgMTc2IDQwMCAxNzZINDY0QzQ5MC41MSAxNzYgNTEyIDE5Ny40OSA1MTIgMjI0VjI4OEM1MTIgMzE0LjUxIDQ5MC41MSAzMzYgNDY0IDMzNkg0MDBDMzczLjQ5IDMzNiAzNTIgMzE0LjUxIDM1MiAyODhWMjgwSDMxNi4yNTJDMjk0LjE2MSAyODAgMjc2LjI1MiAyOTcuOTA5IDI3Ni4yNTIgMzIwVjM3NkMyNzYuMjUyIDQyMC4xODMgMjQwLjQzNSA0NTYgMTk2LjI1MiA0NTZIMTYwVjQ2NEMxNjAgNDkwLjUxIDEzOC41MSA1MTIgMTEyIDUxMkg0OEMyMS40OTAzIDUxMiAwIDQ5MC41MSAwIDQ2NFY0MDBDMCAzNzMuNDkgMjEuNDkwMyAzNTIgNDggMzUySDExMkMxMzguNTEgMzUyIDE2MCAzNzMuNDkgMTYwIDQwMFY0MDhIMTk2LjI1MkMyMTMuOTI1IDQwOCAyMjguMjUyIDM5My42NzMgMjI4LjI1MiAzNzZWMzIwQzIyOC4yNTIgMjk0Ljc4NCAyMzguODU5IDI3Mi4wNDQgMjU1Ljg1MyAyNTZDMjM4Ljg1OSAyMzkuOTU2IDIyOC4yNTIgMjE3LjIxNiAyMjguMjUyIDE5MlYxMzZDMjI4LjI1MiAxMTguMzI3IDIxMy45MjUgMTA0IDE5Ni4yNTIgMTA0SDE2MFYxMTJDMTYwIDEzOC41MSAxMzguNTEgMTYwIDExMiAxNjBINDhDMjEuNDkwMyAxNjAgMCAxMzguNTEgMCAxMTJWNDhaTTEwNCA0OEMxMDguNDE4IDQ4IDExMiA1MS41ODE3IDExMiA1NlYxMDRDMTEyIDEwOC40MTggMTA4LjQxOCAxMTIgMTA0IDExMkg1NkM1MS41ODE3IDExMiA0OCAxMDguNDE4IDQ4IDEwNFY1NkM0OCA1MS41ODE3IDUxLjU4MTcgNDggNTYgNDhIMTA0Wk00NTYgMjI0QzQ2MC40MTggMjI0IDQ2NCAyMjcuNTgyIDQ2NCAyMzJWMjgwQzQ2NCAyODQuNDE4IDQ2MC40MTggMjg4IDQ1NiAyODhINDA4QzQwMy41ODIgMjg4IDQwMCAyODQuNDE4IDQwMCAyODBWMjMyQzQwMCAyMjcuNTgyIDQwMy41ODIgMjI0IDQwOCAyMjRINDU2Wk0xMTIgNDA4QzExMiA0MDMuNTgyIDEwOC40MTggNDAwIDEwNCA0MDBINTZDNTEuNTgxNyA0MDAgNDggNDAzLjU4MiA0OCA0MDhWNDU2QzQ4IDQ2MC40MTggNTEuNTgxNyA0NjQgNTYgNDY0SDEwNEMxMDguNDE4IDQ2NCAxMTIgNDYwLjQxOCAxMTIgNDU2VjQwOFoiIGZpbGw9IiM1NEI4QzkiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMTc3XzUxOCI+CjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo="},"displayName":"Merge","typeVersion":3,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":38,"icon":"fa:pen","name":"n8n-nodes-base.set","codex":{"data":{"alias":["Set","JS","JSON","Filter","Transform","Map"],"resources":{"generic":[{"url":"https://n8n.io/blog/learn-to-automate-your-factorys-incident-reporting-a-step-by-step-guide/","icon":"🏭","label":"Learn to Automate Your Factory's Incident Reporting: A Step by Step Guide"},{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/automatically-pulling-and-visualizing-data-with-n8n/","icon":"📈","label":"Automatically pulling and visualizing data with n8n"},{"url":"https://n8n.io/blog/database-monitoring-and-alerting-with-n8n/","icon":"📡","label":"Database Monitoring and Alerting with n8n"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/how-to-build-a-low-code-self-hosted-url-shortener/","icon":"🔗","label":"How to build a low-code, self-hosted URL shortener in 3 steps"},{"url":"https://n8n.io/blog/automate-your-data-processing-pipeline-in-9-steps-with-n8n/","icon":"⚙️","label":"Automate your data processing pipeline in 9 steps"},{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/building-an-expense-tracking-app-in-10-minutes/","icon":"📱","label":"Building an expense tracking app in 10 minutes"},{"url":"https://n8n.io/blog/the-ultimate-guide-to-automate-your-video-collaboration-with-whereby-mattermost-and-n8n/","icon":"📹","label":"The ultimate guide to automate your video collaboration with Whereby, Mattermost, and n8n"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/learn-to-build-powerful-api-endpoints-using-webhooks/","icon":"🧰","label":"Learn to Build Powerful API Endpoints Using Webhooks"},{"url":"https://n8n.io/blog/how-a-membership-development-manager-automates-his-work-and-investments/","icon":"📈","label":"How a Membership Development Manager automates his work and investments"},{"url":"https://n8n.io/blog/a-low-code-bitcoin-ticker-built-with-questdb-and-n8n-io/","icon":"📈","label":"A low-code bitcoin ticker built with QuestDB and n8n.io"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/benefits-of-automation-and-n8n-an-interview-with-hubspots-hugh-durkin/","icon":"🎖","label":"Benefits of automation and n8n: An interview with HubSpot's Hugh Durkin"},{"url":"https://n8n.io/blog/how-goomer-automated-their-operations-with-over-200-n8n-workflows/","icon":"🛵","label":"How Goomer automated their operations with over 200 n8n workflows"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.set/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Data Transformation"]}}},"group":"[\"input\"]","defaults":{"name":"Edit Fields"},"iconData":{"icon":"pen","type":"icon"},"displayName":"Edit Fields (Set)","typeVersion":3,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":39,"icon":"fa:sync","name":"n8n-nodes-base.splitInBatches","codex":{"data":{"alias":["Loop","Concatenate","Batch","Split","Split In Batches"],"resources":{"generic":[{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/benefits-of-automation-and-n8n-an-interview-with-hubspots-hugh-durkin/","icon":"🎖","label":"Benefits of automation and n8n: An interview with HubSpot's Hugh Durkin"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.splitinbatches/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Flow"]}}},"group":"[\"organization\"]","defaults":{"name":"Loop Over Items","color":"#007755"},"iconData":{"icon":"sync","type":"icon"},"displayName":"Loop Over Items (Split in Batches)","typeVersion":3,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":49,"icon":"file:telegram.svg","name":"n8n-nodes-base.telegram","codex":{"data":{"alias":["human","form","wait","hitl","approval"],"resources":{"generic":[{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/world-poetry-day-workflow/","icon":"📜","label":"Celebrating World Poetry Day with a daily poem in Telegram"},{"url":"https://n8n.io/blog/using-automation-to-boost-productivity-in-the-workplace/","icon":"💪","label":"Using Automation to Boost Productivity in the Workplace"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/creating-scheduled-text-affirmations-with-n8n/","icon":"🤟","label":"Creating scheduled text affirmations with n8n"},{"url":"https://n8n.io/blog/creating-telegram-bots-with-n8n-a-no-code-platform/","icon":"💬","label":"Creating Telegram Bots with n8n, a No-Code Platform"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/"}],"credentialDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/credentials/telegram/"}]},"categories":["Communication","HITL"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"HITL":["Human in the Loop"]}}},"group":"[\"output\"]","defaults":{"name":"Telegram"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiB2aWV3Qm94PSIwIDAgNjYgNjYiPjx1c2UgeGxpbms6aHJlZj0iI2EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9ImEiIG92ZXJmbG93PSJ2aXNpYmxlIj48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0ibm9uZSI+PHBhdGggZmlsbD0iIzM3YWVlMiIgZD0iTTAgMzJjMCAxNy42NzMgMTQuMzI3IDMyIDMyIDMyczMyLTE0LjMyNyAzMi0zMlM0OS42NzMgMCAzMiAwIDAgMTQuMzI3IDAgMzIiLz48cGF0aCBmaWxsPSIjYzhkYWVhIiBkPSJtMjEuNjYxIDM0LjMzOCAzLjc5NyAxMC41MDhzLjQ3NS45ODMuOTgzLjk4MyA4LjA2OC03Ljg2NCA4LjA2OC03Ljg2NGw4LjQwNy0xNi4yMzctMjEuMTE5IDkuODk4eiIvPjxwYXRoIGZpbGw9IiNhOWM2ZDgiIGQ9Im0yNi42OTUgMzcuMDM0LS43MjkgNy43NDZzLS4zMDUgMi4zNzMgMi4wNjggMGw0LjY0NC00LjIwMyIvPjxwYXRoIGQ9Im0yMS43MyAzNC43MTItNy44MDktMi41NDVzLS45MzItLjM3OC0uNjMzLTEuMjM3Yy4wNjItLjE3Ny4xODYtLjMyOC41NTktLjU4OCAxLjczMS0xLjIwNiAzMi4wMjgtMTIuMDk2IDMyLjAyOC0xMi4wOTZzLjg1Ni0uMjg4IDEuMzYxLS4wOTdjLjIzMS4wODguMzc4LjE4Ny41MDMuNTQ4LjA0NS4xMzIuMDcxLjQxMS4wNjguNjg5LS4wMDMuMjAxLS4wMjcuMzg2LS4wNDUuNjc4LS4xODQgMi45NzgtNS43MDYgMjUuMTk4LTUuNzA2IDI1LjE5OHMtLjMzIDEuMy0xLjUxNCAxLjM0NWMtLjQzMi4wMTYtLjk1Ni0uMDcxLTEuNTgyLS42MS0yLjMyMy0xLjk5OC0xMC4zNTItNy4zOTQtMTIuMTI2LTguNThhLjM0LjM0IDAgMCAxLS4xNDYtLjIzOWMtLjAyNS0uMTI1LjEwOC0uMjguMTA4LS4yOHMxMy45OC0xMi40MjcgMTQuMzUyLTEzLjczMWMuMDI5LS4xMDEtLjA3OS0uMTUxLS4yMjYtLjEwNy0uOTI5LjM0Mi0xNy4wMjUgMTAuNTA2LTE4LjgwMSAxMS42MjktLjEwNC4wNjYtLjM5NS4wMjMtLjM5NS4wMjMiLz48L2c+PC9zeW1ib2w+PC9zdmc+"},"displayName":"Telegram","typeVersion":1,"nodeCategories":[{"id":6,"name":"Communication"},{"id":28,"name":"HITL"}]},{"id":50,"icon":"file:telegram.svg","name":"n8n-nodes-base.telegramTrigger","codex":{"data":{"resources":{"generic":[{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/creating-telegram-bots-with-n8n-a-no-code-platform/","icon":"💬","label":"Creating Telegram Bots with n8n, a No-Code Platform"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.telegramtrigger/"}],"credentialDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/credentials/telegram/"}]},"categories":["Communication"],"nodeVersion":"1.0","codexVersion":"1.0"}},"group":"[\"trigger\"]","defaults":{"name":"Telegram Trigger"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiB2aWV3Qm94PSIwIDAgNjYgNjYiPjx1c2UgeGxpbms6aHJlZj0iI2EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9ImEiIG92ZXJmbG93PSJ2aXNpYmxlIj48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0ibm9uZSI+PHBhdGggZmlsbD0iIzM3YWVlMiIgZD0iTTAgMzJjMCAxNy42NzMgMTQuMzI3IDMyIDMyIDMyczMyLTE0LjMyNyAzMi0zMlM0OS42NzMgMCAzMiAwIDAgMTQuMzI3IDAgMzIiLz48cGF0aCBmaWxsPSIjYzhkYWVhIiBkPSJtMjEuNjYxIDM0LjMzOCAzLjc5NyAxMC41MDhzLjQ3NS45ODMuOTgzLjk4MyA4LjA2OC03Ljg2NCA4LjA2OC03Ljg2NGw4LjQwNy0xNi4yMzctMjEuMTE5IDkuODk4eiIvPjxwYXRoIGZpbGw9IiNhOWM2ZDgiIGQ9Im0yNi42OTUgMzcuMDM0LS43MjkgNy43NDZzLS4zMDUgMi4zNzMgMi4wNjggMGw0LjY0NC00LjIwMyIvPjxwYXRoIGQ9Im0yMS43MyAzNC43MTItNy44MDktMi41NDVzLS45MzItLjM3OC0uNjMzLTEuMjM3Yy4wNjItLjE3Ny4xODYtLjMyOC41NTktLjU4OCAxLjczMS0xLjIwNiAzMi4wMjgtMTIuMDk2IDMyLjAyOC0xMi4wOTZzLjg1Ni0uMjg4IDEuMzYxLS4wOTdjLjIzMS4wODguMzc4LjE4Ny41MDMuNTQ4LjA0NS4xMzIuMDcxLjQxMS4wNjguNjg5LS4wMDMuMjAxLS4wMjcuMzg2LS4wNDUuNjc4LS4xODQgMi45NzgtNS43MDYgMjUuMTk4LTUuNzA2IDI1LjE5OHMtLjMzIDEuMy0xLjUxNCAxLjM0NWMtLjQzMi4wMTYtLjk1Ni0uMDcxLTEuNTgyLS42MS0yLjMyMy0xLjk5OC0xMC4zNTItNy4zOTQtMTIuMTI2LTguNThhLjM0LjM0IDAgMCAxLS4xNDYtLjIzOWMtLjAyNS0uMTI1LjEwOC0uMjguMTA4LS4yOHMxMy45OC0xMi40MjcgMTQuMzUyLTEzLjczMWMuMDI5LS4xMDEtLjA3OS0uMTUxLS4yMjYtLjEwNy0uOTI5LjM0Mi0xNy4wMjUgMTAuNTA2LTE4LjgwMSAxMS42MjktLjEwNC4wNjYtLjM5NS4wMjMtLjM5NS4wMjMiLz48L2c+PC9zeW1ib2w+PC9zdmc+"},"displayName":"Telegram Trigger","typeVersion":1,"nodeCategories":[{"id":6,"name":"Communication"}]},{"id":514,"icon":"fa:pause-circle","name":"n8n-nodes-base.wait","codex":{"data":{"alias":["pause","sleep","delay","timeout"],"resources":{"generic":[{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers","Flow"]}}},"group":"[\"organization\"]","defaults":{"name":"Wait","color":"#804050"},"iconData":{"icon":"pause-circle","type":"icon"},"displayName":"Wait","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":565,"icon":"fa:sticky-note","name":"n8n-nodes-base.stickyNote","codex":{"data":{"alias":["Comments","Notes","Sticky"],"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"input\"]","defaults":{"name":"Sticky Note","color":"#FFD233"},"iconData":{"icon":"sticky-note","type":"icon"},"displayName":"Sticky Note","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":834,"icon":"file:code.svg","name":"n8n-nodes-base.code","codex":{"data":{"alias":["cpde","Javascript","JS","Python","Script","Custom Code","Function"],"details":"The Code node allows you to execute JavaScript in your workflow.","resources":{"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/"}]},"categories":["Development","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers","Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Code"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xMTcxXzQ0MSkiPgo8cGF0aCBkPSJNMTcwLjI4MyA0OEgxOTYuNUMyMDMuMTI3IDQ4IDIwOC41IDQyLjYyNzQgMjA4LjUgMzZWMTJDMjA4LjUgNS4zNzI1OCAyMDMuMTI3IDAgMTk2LjUgMEgxNzAuMjgzQzEyNi4xIDAgOTAuMjgzIDM1LjgxNzIgOTAuMjgzIDgwVjE3NkM5MC4yODMgMjA2LjkyOCA2NS4yMTA5IDIzMiAzNC4yODMgMjMySDIzQzE2LjM3MjYgMjMyIDExIDIzNy4zNzIgMTEgMjQ0VjI2OEMxMSAyNzQuNjI3IDE2LjM3MjQgMjgwIDIyLjk5OTYgMjgwTDM0LjI4MyAyODBDNjUuMjEwOSAyODAgOTAuMjgzIDMwNS4wNzIgOTAuMjgzIDMzNlY0NDBDOTAuMjgzIDQ3OS43NjQgMTIyLjUxOCA1MTIgMTYyLjI4MyA1MTJIMTk2LjVDMjAzLjEyNyA1MTIgMjA4LjUgNTA2LjYyNyAyMDguNSA1MDBWNDc2QzIwOC41IDQ2OS4zNzMgMjAzLjEyNyA0NjQgMTk2LjUgNDY0SDE2Mi4yODNDMTQ5LjAyOCA0NjQgMTM4LjI4MyA0NTMuMjU1IDEzOC4yODMgNDQwVjMzNkMxMzguMjgzIDMwOS4wMjIgMTI4LjAxMSAyODQuNDQzIDExMS4xNjQgMjY1Ljk2MUMxMDYuMTA5IDI2MC40MTYgMTA2LjEwOSAyNTEuNTg0IDExMS4xNjQgMjQ2LjAzOUMxMjguMDExIDIyNy41NTcgMTM4LjI4MyAyMDIuOTc4IDEzOC4yODMgMTc2VjgwQzEzOC4yODMgNjIuMzI2OSAxNTIuNjEgNDggMTcwLjI4MyA0OFoiIGZpbGw9IiNGRjk5MjIiLz4KPHBhdGggZD0iTTMwNSAzNkMzMDUgNDIuNjI3NCAzMTAuMzczIDQ4IDMxNyA0OEgzNDIuOTc5QzM2MC42NTIgNDggMzc0Ljk3OCA2Mi4zMjY5IDM3NC45NzggODBWMTc2QzM3NC45NzggMjAyLjk3OCAzODUuMjUxIDIyNy41NTcgNDAyLjA5OCAyNDYuMDM5QzQwNy4xNTMgMjUxLjU4NCA0MDcuMTUzIDI2MC40MTYgNDAyLjA5OCAyNjUuOTYxQzM4NS4yNTEgMjg0LjQ0MyAzNzQuOTc4IDMwOS4wMjIgMzc0Ljk3OCAzMzZWNDMyQzM3NC45NzggNDQ5LjY3MyAzNjAuNjUyIDQ2NCAzNDIuOTc5IDQ2NEgzMTdDMzEwLjM3MyA0NjQgMzA1IDQ2OS4zNzMgMzA1IDQ3NlY1MDBDMzA1IDUwNi42MjcgMzEwLjM3MyA1MTIgMzE3IDUxMkgzNDIuOTc5QzM4Ny4xNjEgNTEyIDQyMi45NzggNDc2LjE4MyA0MjIuOTc4IDQzMlYzMzZDNDIyLjk3OCAzMDUuMDcyIDQ0OC4wNTEgMjgwIDQ3OC45NzkgMjgwSDQ5MEM0OTYuNjI3IDI4MCA1MDIgMjc0LjYyOCA1MDIgMjY4VjI0NEM1MDIgMjM3LjM3MyA0OTYuNjI4IDIzMiA0OTAgMjMyTDQ3OC45NzkgMjMyQzQ0OC4wNTEgMjMyIDQyMi45NzggMjA2LjkyOCA0MjIuOTc4IDE3NlY4MEM0MjIuOTc4IDM1LjgxNzIgMzg3LjE2MSAwIDM0Mi45NzkgMEgzMTdDMzEwLjM3MyAwIDMwNSA1LjM3MjU4IDMwNSAxMlYzNloiIGZpbGw9IiNGRjk5MjIiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMTcxXzQ0MSI+CjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo="},"displayName":"Code","typeVersion":2,"nodeCategories":[{"id":5,"name":"Development"},{"id":9,"name":"Core Nodes"}]},{"id":1236,"icon":"file:aggregate.svg","name":"n8n-nodes-base.aggregate","codex":{"data":{"alias":["Aggregate","Combine","Flatten","Transform","Array","List","Item"],"details":"","resources":{"generic":[],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.aggregate/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Aggregate"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJub25lIj48ZyBmaWxsPSIjRkY2RDVBIiBjbGlwLXBhdGg9InVybCgjYSkiPjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTMyIDE0OGMwLTYuNjI3IDUuMzczLTEyIDEyLTEyaDE0NmM2LjYyNyAwIDEyIDUuMzczIDEyIDEydjI0YzAgNi42MjctNS4zNzMgMTItMTIgMTJINDRjLTYuNjI3IDAtMTItNS4zNzMtMTItMTJ6bTAgOTZjMC02LjYyNyA1LjM3My0xMiAxMi0xMmgxNDZjNi42MjcgMCAxMiA1LjM3MyAxMiAxMnYyNGMwIDYuNjI3LTUuMzczIDEyLTEyIDEySDQ0Yy02LjYyNyAwLTEyLTUuMzczLTEyLTEyem0wIDk2YzAtNi42MjcgNS4zNzMtMTIgMTItMTJoMTQ2YzYuNjI3IDAgMTIgNS4zNzMgMTIgMTJ2MjRjMCA2LjYyNy01LjM3MyAxMi0xMiAxMkg0NGMtNi42MjcgMC0xMi01LjM3My0xMi0xMnoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGQ9Ik03NCA3NmMwIDYuNjI3IDUuMzczIDEyIDEyIDEyaDExNi4yMTdjMTcuNjczIDAgMzIgMTQuMzI3IDMyIDMydjU2YzAgMjYuOTc4IDEwLjI3MiA1MS41NTcgMjcuMTE5IDcwLjAzOSA1LjA1NSA1LjU0NSA1LjA1NSAxNC4zNzcgMCAxOS45MjItMTYuODQ3IDE4LjQ4Mi0yNy4xMTkgNDMuMDYxLTI3LjExOSA3MC4wMzl2NTZjMCAxNy42NzMtMTQuMzI3IDMyLTMyIDMySDg2Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0YzAgNi42MjcgNS4zNzMgMTIgMTIgMTJoMTE2LjIxN2M0NC4xODMgMCA4MC0zNS44MTcgODAtODB2LTU2YzAtMzAuOTI4IDI1LjA3Mi01NiA1Ni01NmE1Ljc4MyA1Ljc4MyAwIDAgMCA1Ljc4My01Ljc4M3YtMzYuNDM0YTUuNzgzIDUuNzgzIDAgMCAwLTUuNzgzLTUuNzgzYy0zMC45MjggMC01Ni0yNS4wNzItNTYtNTZ2LTU2YzAtNDQuMTgzLTM1LjgxNy04MC04MC04MEg4NmMtNi42MjcgMC0xMiA1LjM3My0xMiAxMnoiLz48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zNzYgMjQ0YzAtNi42MjcgNS4zNzMtMTIgMTItMTJoMTEyYzYuNjI3IDAgMTIgNS4zNzMgMTIgMTJ2MjRjMCA2LjYyNy01LjM3MyAxMi0xMiAxMkgzODhjLTYuNjI3IDAtMTItNS4zNzMtMTItMTJ6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L2c+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDUxMnY1MTJIMHoiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4="},"displayName":"Aggregate","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":1239,"icon":"file:splitOut.svg","name":"n8n-nodes-base.splitOut","codex":{"data":{"alias":["Split","Nested","Transform","Array","List","Item"],"details":"","resources":{"generic":[],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.splitout/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Split Out"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJub25lIj48ZyBmaWxsPSIjOUI2REQ1IiBjbGlwLXBhdGg9InVybCgjYSkiPjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTQ4MCAxNDhjMC02LjYyNy01LjM3My0xMi0xMi0xMkgzMjJjLTYuNjI3IDAtMTIgNS4zNzMtMTIgMTJ2MjRjMCA2LjYyNyA1LjM3MyAxMiAxMiAxMmgxNDZjNi42MjcgMCAxMi01LjM3MyAxMi0xMnptMCA5NmMwLTYuNjI3LTUuMzczLTEyLTEyLTEySDMyMmMtNi42MjcgMC0xMiA1LjM3My0xMiAxMnYyNGMwIDYuNjI3IDUuMzczIDEyIDEyIDEyaDE0NmM2LjYyNyAwIDEyLTUuMzczIDEyLTEyem0wIDk2YzAtNi42MjctNS4zNzMtMTItMTItMTJIMzIyYy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0YzAgNi42MjcgNS4zNzMgMTIgMTIgMTJoMTQ2YzYuNjI3IDAgMTItNS4zNzMgMTItMTJ6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNNDM4IDc2YzAgNi42MjctNS4zNzMgMTItMTIgMTJIMzA5Ljc4M2MtMTcuNjczIDAtMzIgMTQuMzI3LTMyIDMydjU2YzAgMjYuOTc4LTEwLjI3MiA1MS41NTctMjcuMTE5IDcwLjAzOS01LjA1NSA1LjU0NS01LjA1NSAxNC4zNzcgMCAxOS45MjIgMTYuODQ3IDE4LjQ4MiAyNy4xMTkgNDMuMDYxIDI3LjExOSA3MC4wMzl2NTZjMCAxNy42NzMgMTQuMzI3IDMyIDMyIDMySDQyNmM2LjYyNyAwIDEyIDUuMzczIDEyIDEydjI0YzAgNi42MjctNS4zNzMgMTItMTIgMTJIMzA5Ljc4M2MtNDQuMTgzIDAtODAtMzUuODE3LTgwLTgwdi01NmMwLTMwLjkyOC0yNS4wNzItNTYtNTYtNTZhNS43ODMgNS43ODMgMCAwIDEtNS43ODMtNS43ODN2LTM2LjQzNGE1Ljc4MyA1Ljc4MyAwIDAgMSA1Ljc4My01Ljc4M2MzMC45MjggMCA1Ni0yNS4wNzIgNTYtNTZ2LTU2YzAtNDQuMTgzIDM1LjgxNy04MCA4MC04MEg0MjZjNi42MjcgMCAxMiA1LjM3MyAxMiAxMnoiLz48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMzYgMjQ0YzAtNi42MjctNS4zNzMtMTItMTItMTJIMTJjLTYuNjI3IDAtMTIgNS4zNzMtMTIgMTJ2MjRjMCA2LjYyNyA1LjM3MyAxMiAxMiAxMmgxMTJjNi42MjcgMCAxMi01LjM3MyAxMi0xMnoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvZz48ZGVmcz48Y2xpcFBhdGggaWQ9ImEiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01MTIgMEgwdjUxMmg1MTJ6Ii8+PC9jbGlwUGF0aD48L2RlZnM+PC9zdmc+"},"displayName":"Split Out","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":1250,"icon":"file:openAi.svg","name":"@n8n/n8n-nodes-langchain.openAi","codex":{"data":{"alias":["LangChain","ChatGPT","Sora","DallE","whisper","audio","transcribe","tts","assistant"],"resources":{"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-langchain.openai/"}]},"categories":["AI","Langchain"],"subcategories":{"AI":["Agents","Miscellaneous","Root Nodes"]}}},"group":"[\"transform\"]","defaults":{"name":"OpenAI"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTM2Ljg2NzEgMTYuMzcxOEMzNy43NzQ2IDEzLjY0OCAzNy40NjIxIDEwLjY2NDIgMzYuMDEwOCA4LjE4NjYxQzMzLjgyODIgNC4zODY1MyAyOS40NDA3IDIuNDMxNDkgMjUuMTU1NiAzLjM1MTUxQzIzLjI0OTMgMS4yMDM5NiAyMC41MTA1IC0wLjAxNzMxNDggMTcuNjM5MiAwLjAwMDE4NTUzM0MxMy4yNTkxIC0wLjAwOTgxNDY4IDkuMzcyNzMgMi44MTAyNSA4LjAyNTIgNi45Nzc4M0M1LjIxMTM5IDcuNTU0MSAyLjc4MjU4IDkuMzE1MzggMS4zNjEzIDExLjgxMTdDLTAuODM3NDkzIDE1LjYwMTggLTAuMzM2MjMyIDIwLjM3OTQgMi42MDEzMyAyMy42Mjk0QzEuNjkzODEgMjYuMzUzMiAyLjAwNjMyIDI5LjMzNzEgMy40NTc2IDMxLjgxNDZDNS42NDAxNSAzNS42MTQ3IDEwLjAyNzcgMzcuNTY5NyAxNC4zMTI4IDM2LjY0OTdDMTYuMjE3OSAzOC43OTczIDE4Ljk1NzkgNDAuMDE4NSAyMS44MjkyIDM5Ljk5OThDMjYuMjExOCA0MC4wMTEgMzAuMDk5NCAzNy4xODg1IDMxLjQ0NjkgMzMuMDE3MUMzNC4yNjA4IDMyLjQ0MDkgMzYuNjg5NiAzMC42Nzk2IDM4LjExMDggMjguMTgzM0M0MC4zMDcxIDI0LjM5MzIgMzkuODA0NiAxOS42MTk0IDM2Ljg2ODMgMTYuMzY5M0wzNi44NjcxIDE2LjM3MThaTTIxLjgzMTcgMzcuMzg2QzIwLjA3OCAzNy4zODg1IDE4LjM3OTIgMzYuNzc0NyAxNy4wMzI5IDM1LjY1MDlDMTcuMDk0MSAzNS42MTg1IDE3LjIwMDQgMzUuNTU5NyAxNy4yNjkxIDM1LjUxNzJMMjUuMjM0MyAzMC45MTcxQzI1LjY0MTggMzAuNjg1OCAyNS44OTE4IDMwLjI1MjEgMjUuODg5MyAyOS43ODMzVjE4LjU1NDNMMjkuMjU1NiAyMC40OTgxQzI5LjI5MTkgMjAuNTE1NiAyOS4zMTU3IDIwLjU1MDYgMjkuMzIwNyAyMC41OTA2VjI5Ljg4OTZDMjkuMzE1NyAzNC4wMjQ3IDI1Ljk2NjggMzcuMzc3MiAyMS44MzE3IDM3LjM4NlpNNS43MjY0IDMwLjUwNzFDNC44NDc2MyAyOC45ODk2IDQuNTMxMzcgMjcuMjEwOCA0LjgzMjYzIDI1LjQ4NDVDNC44OTEzOCAyNS41MTk1IDQuOTk1MTMgMjUuNTgzMiA1LjA2ODg4IDI1LjYyNTdMMTMuMDM0MSAzMC4yMjU4QzEzLjQzNzggMzAuNDYyMSAxMy45Mzc4IDMwLjQ2MjEgMTQuMzQyOCAzMC4yMjU4TDI0LjA2NjggMjQuNjEwN1YyOC40OTgzQzI0LjA2OTMgMjguNTM4MyAyNC4wNTA1IDI4LjU3NyAyNC4wMTkzIDI4LjYwMkwxNS45Njc5IDMzLjI1MDlDMTIuMzgxNSAzNS4zMTU5IDcuODAxNDQgMzQuMDg4NCA1LjcyNzY1IDMwLjUwNzFINS43MjY0Wk0zLjYzMDEgMTMuMTIwNUM0LjUwNTEyIDExLjYwMDQgNS44ODY0IDEwLjQzNzkgNy41MzE0NCA5LjgzNDE1QzcuNTMxNDQgOS45MDI5IDcuNTI3NjkgMTAuMDI0MSA3LjUyNzY5IDEwLjEwOTJWMTkuMzEwNkM3LjUyNTE5IDE5Ljc3ODEgNy43NzUxOSAyMC4yMTE5IDguMTgxNDUgMjAuNDQzMUwxNy45MDU0IDI2LjA1N0wxNC41MzkxIDI4LjAwMDhDMTQuNTA1MyAyOC4wMjMzIDE0LjQ2MjggMjguMDI3IDE0LjQyNTMgMjguMDEwOEw2LjM3MjY2IDIzLjM1ODJDMi43OTM4MyAyMS4yODU2IDEuNTY2MzEgMTYuNzA2OCAzLjYyODg1IDEzLjEyMTdMMy42MzAxIDEzLjEyMDVaTTMxLjI4ODIgMTkuNTU2OUwyMS41NjQyIDEzLjk0MTdMMjQuOTMwNiAxMS45OTkyQzI0Ljk2NDMgMTEuOTc2NyAyNS4wMDY4IDExLjk3MjkgMjUuMDQ0MyAxMS45ODkyTDMzLjA5NyAxNi42MzhDMzYuNjgyMSAxOC43MDkzIDM3LjkxMDggMjMuMjk1NyAzNS44Mzk1IDI2Ljg4MDhDMzQuOTYzMyAyOC4zOTgzIDMzLjU4MzIgMjkuNTYwOCAzMS45Mzk1IDMwLjE2NThWMjAuNjg5NEMzMS45NDMyIDIwLjIyMTkgMzEuNjk0NSAxOS43ODk0IDMxLjI4OTQgMTkuNTU2OUgzMS4yODgyWk0zNC42MzgzIDE0LjUxNDJDMzQuNTc5NSAxNC40NzggMzQuNDc1OCAxNC40MTU1IDM0LjQwMiAxNC4zNzNMMjYuNDM2OCA5Ljc3Mjg5QzI2LjAzMzEgOS41MzY2NCAyNS41MzMxIDkuNTM2NjQgMjUuMTI4MSA5Ljc3Mjg5TDE1LjQwNDEgMTUuMzg4VjExLjUwMDRDMTUuNDAxNiAxMS40NjA0IDE1LjQyMDQgMTEuNDIxNyAxNS40NTE2IDExLjM5NjdMMjMuNTAzIDYuNzUxNThDMjcuMDg5NCA0LjY4Mjc5IDMxLjY3NDUgNS45MTQwNiAzMy43NDIgOS41MDE2NEMzNC42MTU4IDExLjAxNjcgMzQuOTMyIDEyLjc5MDUgMzQuNjM1OCAxNC41MTQySDM0LjYzODNaTTEzLjU3NDEgMjEuNDQzMUwxMC4yMDY1IDE5LjQ5OTRDMTAuMTcwMiAxOS40ODE5IDEwLjE0NjUgMTkuNDQ2OCAxMC4xNDE1IDE5LjQwNjhWMTAuMTA3OUMxMC4xNDQgNS45Njc4MSAxMy41MDI4IDIuNjEyNzQgMTcuNjQyOSAyLjYxNTI0QzE5LjM5NDIgMi42MTUyNCAyMS4wODkyIDMuMjMwMjUgMjIuNDM1NSA0LjM1MDI4QzIyLjM3NDMgNC4zODI3OCAyMi4yNjkzIDQuNDQxNTMgMjIuMTk5MiA0LjQ4NDAzTDE0LjIzNDEgOS4wODQxM0MxMy44MjY2IDkuMzE1MzggMTMuNTc2NiA5Ljc0Nzg5IDEzLjU3OTEgMTAuMjE2N0wxMy41NzQxIDIxLjQ0MDZWMjEuNDQzMVpNMTUuNDAyOSAxNy41MDA2TDE5LjczNDIgMTQuOTk5M0wyNC4wNjU1IDE3LjQ5OTNWMjIuNTAwN0wxOS43MzQyIDI1LjAwMDdMMTUuNDAyOSAyMi41MDA3VjE3LjUwMDZaIiBmaWxsPSJibGFjayIvPgo8L3N2Zz4K"},"displayName":"OpenAI","typeVersion":2,"nodeCategories":[{"id":25,"name":"AI"},{"id":26,"name":"Langchain"}]}],"categories":[{"id":35,"name":"Document Extraction"},{"id":47,"name":"AI Chatbot"}],"image":[{"id":4911,"url":"https://n8niostorageaccount.blob.core.windows.net/n8nio-strapi-blobs-prod/assets/image_087334284a.png"}]}}