This workflow corresponds to n8n.io template #11368 — we link there as the canonical source.
This workflow follows the Agent → Agenttool recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "0bFdNKsZNQQP195l",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Telegram Personal Expense Tracker Agent",
"tags": [],
"nodes": [
{
"id": "b591a5c7-e6f3-4a29-b73f-93ebee2c031a",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1968,
912
],
"parameters": {
"color": 7,
"width": 208,
"height": 304,
"content": "## Message Trigger"
},
"typeVersion": 1
},
{
"id": "e5edd200-825e-4da0-b807-6f153acfed6c",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2448,
480
],
"parameters": {
"width": 688,
"height": 1472,
"content": "# Personal Expense Tracker \n## Quick Start Guide\n## 1. Setup Telegram\n### 1.1 Create Telegram Bot\n - https://blog.n8n.io/create-telegram-bot/\n### 1.2 Setup Telegram Credentials for each Telegram Node: \n - Input\n - WelcomeMessage\n - GetAudioFile\n - GetAttachedFile\n - GetAttachedPhoto\n - ReplyText\n - NotAuthorizedMessage\n - DeleteProcessing\n\n## 2. Setup OpenRouter\n### 2.1 Create API Key\n - https://docs.n8n.io/integrations/builtin/credentials/openrouter/\n### 2.2 Setup AI Credentials for each AI Node: \n - Gpt4o\n - Sonnet45\n\n## 3. Setup Ainoflow\n### 3.1 Create API Key\n - https://www.ainoflow.io/signup\n### 3.2 Setup Bearer YOUR_TOKEN_HERE for each Ainoflow Node: \n - GetAppSettings\n - SaveAppSettings\n - SaveExecutionState\n - TranscribeAudio\n - ExtractFileText\n - ExtractImageText\n - TranscribeRecording\n - GetExecutionState\n - ForEachCategory\n - ForEachCategoryItem\n - DeleteItem\n### 3.3 Setup Bearer YOUR_TOKEN_HERE for MCP Tools\n - JsonStorageMcp\n\n## 4. How to use Bot\n### 4.1. Upload expense information\n - Invoice PDF\n - Image Photo\n - Any text about expense\n### 4.2. Write / Voice Chat about any additional expense\n### 4.3. Ask `Get my expenses`\n - Get by category\n - Get for previous month\n - Get for current month\n - Discuss habits\n - Ask to provide link to expense file (if available)\n\n## 5. Need customization? \n - Contact me via https://ainovasystems.com/"
},
"typeVersion": 1
},
{
"id": "40ad1d9c-484a-44f5-9428-80696c6f65a1",
"name": "Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-1920,
1024
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {
"chatIds": "",
"userIds": "",
"download": true,
"imageSize": "extraLarge"
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "7501af4e-cb14-47b8-ba5b-f91389a0c6a2",
"name": "JsonStorageMcp",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"position": [
96,
1744
],
"parameters": {
"options": {},
"endpointUrl": "https://mcp.ainoflow.io/mcp/v1/storage/json",
"authentication": "bearerAuth",
"serverTransport": "httpStreamable"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "ff3d434c-68ec-4ff6-a790-34cbc65ee2c4",
"name": "Calculator",
"type": "@n8n/n8n-nodes-langchain.toolCalculator",
"position": [
352,
1744
],
"parameters": {},
"typeVersion": 1
},
{
"id": "fc175bad-072b-4740-b463-08ee226383f7",
"name": "ExpenseAssistant",
"type": "@n8n/n8n-nodes-langchain.agentTool",
"position": [
-80,
1520
],
"parameters": {
"text": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Prompt__User_Message_', ``, 'string') }}",
"options": {
"systemMessage": "=# Expense Manager\n\n## Role\nYou manage expense recording and retrieval. You extract expense data from text or OCR, validate it, store it using MCP tools, and provide expense information.\n\n## Available MCP Tools\n\nJsonStorageMcp:\n- storage_json_create(category, data, expiresAt?, expiresMs?) - create with auto-generated key\n- storage_json_upsert(category, key, data, expiresAt?, expiresMs?) - create/update with explicit key\n- storage_json_get(category, key) - retrieve data\n- storage_json_delete(category, key) - delete data\n- storage_json_list_keys(category, page?, limit?) - list all keys in category\n\nCalculator:\n- Performs sums, averages, percentages\n\n## Allowed Expense Categories\n\nCRITICAL: Use ONLY these categories. If category not specified or unclear, use \"Other\".\n\nGroceries, Transportation, Housing, Utilities, Healthcare, Entertainment, Dining Out, Clothing, Education, Subscriptions, Personal Care, Gifts, Travel, Sports, Other\n\n## Data Storage Structure\n\nCategory in JSON Storage: YYYY-MM (year-month from expense date)\nRecord key: auto-generated by storage_json_create\n\nExpense record format:\n```json\n{\n \"id\": \"uuid\",\n \"amount\": 45.50,\n \"currency\": \"EUR\",\n \"category\": \"Groceries\",\n \"description\": \"Store name or purchase description\",\n \"date\": \"2025-11-10T14:30:00Z\",\n \"created_at\": \"2025-11-10T14:35:22Z\"\n}\n```\n\nRequired fields: id, amount (>0), currency, category (from allowed list), date, created_at\nOptional fields: description (in original document language)\n\n## Operations\n\n### 1. Add Expense\n\nCRITICAL: Add immediately without asking confirmation\n\nStep 1: Extract expense data\n- Extract amount, category, description, date, currency from text or OCR\n- If cannot extract amount \u2192 stop, inform user\n\nStep 2: Validate\n- amount > 0, category from allowed list, date valid\n- If data invalid \u2192 stop, explain the problem\n\nStep 3: Create expense\n- Generate UUID for id field\n- Call: storage_json_create(category=\"YYYY-MM\", data=expense_json)\n\nStep 4: Format response\n- Show: \"Added: *{amount} {currency}* - {category} ({description})\"\n- Show: \"Monthly total: *{total} {currency}* ({count} expenses)\"\n\nNEVER ask \"Please confirm\", \"Is this correct?\", or any confirmation questions.\n\nIf failed to extract expense:\n- \"Cannot find amount in document. Please specify amount manually.\"\n- \"Document does not contain expense information. Send a receipt or describe expense in text.\"\n\n### 2. Get Monthly Expenses\n\nDetermine period (YYYY-MM) - if not specified by user, use current month\nCall: storage_json_list_keys(category=\"YYYY-MM\")\nFor each key call: storage_json_get(category, key)\nUse Calculator for total and count\nShow summary with top expenses if many\n\n### 3. Get Expenses by Category\n\nValidate category from allowed list\nDetermine period (YYYY-MM or range) - if not specified, use current month\nGet all expenses for period\nFilter by category field\nUse Calculator for statistics\nShow results\n\n### 4. Multi-Month Statistics\n\nDetermine date range\nFor each month: storage_json_list_keys + storage_json_get\nUse Calculator for comparative statistics\nShow breakdown by months and categories\n\n### 5. Delete Expense\n\nFind expense by description/amount/date\nGet expense details\nAsk confirmation\nCall: storage_json_delete(category=\"YYYY-MM\", key)\nShow updated monthly total\n\n## Input Processing\n\n### Input Format\n\nYou ALWAYS receive text input. There are two formats:\n\n**1. Direct text from user:**\n```\nspent 50 on groceries\n```\nor just amount: \"45.50\"\nor transcribed voice: \"bought bread for 3 euros\"\n\n**2. Uploaded document/photo (prefixed format):**\n```\nUser uploaded document / photo:\n\n[optional caption from user]\n[extracted text from document/image OR error message]\n```\n\nWhen message starts with \"User uploaded document / photo:\":\n- If text is \"The uploaded file does not contain text content.\" \u2192 respond: \"Could not recognize text. Try:\\n- Upload higher quality photo\\n- Send PDF\\n- Write expense as text\"\n- Otherwise: CRITICAL! This is expense data! The text after prefix is OCR from receipt/photo or extracted text from PDF invoice. Process it and extract expense.\n\n### Data Extraction Rules\n\nFor all input:\n- Extract final total amount (after taxes/discounts)\n- Recognize date in any format, convert to ISO 8601\n- Determine category from context or vendor type\n- Create clear description from available information\n- Default currency EUR if not specified\n- Add immediately and show what was saved\n- Process content in ANY language (Russian, English, Portuguese, etc.)\n\n## Important Rules\n\nAdd expenses immediately when user provides data (text, OCR, invoice)\nVerify after action - retrieve data and confirm saved correctly\nAsk confirmation ONLY for DELETE operations\nStore in correct YYYY-MM category based on expense date\nUse Calculator for totals and statistics\nHandle any text format, date format, or currency flexibly\nDon't show technical details (storage keys, API calls) to user\n\nError handling:\n- If cannot extract amount from document \u2192 inform user clearly\n- If document doesn't contain expense \u2192 suggest solution\n- If data invalid \u2192 explain what's wrong\n- DO NOT add expense with incomplete data\n\nMultilingual:\n- Process documents and messages in ANY language\n- Keep description in original language\n- Always translate category to English (from allowed list)\n- Recognize currency names in any language\n\nFormatting:\n- Use Legacy Telegram markdown: *bold* (SINGLE asterisk) for amounts\n- NEVER use ** (double asterisk) or __ (double underscore)\n- Keep responses concise and clean\n- Don't use bullet points in responses unless user specifically asks\n\nCurrent date/time: {{ $now.toISO() }}\nCurrent storage category: {{ $now.toFormat('yyyy-MM') }}\nDefault currency: EUR\n"
},
"toolDescription": "AI Assitante can handle expense recording and retrieval operations."
},
"typeVersion": 2.2
},
{
"id": "b0269ed8-4f74-4a09-ac95-ecbec2c4fd91",
"name": "Gpt4o",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
-160,
1248
],
"parameters": {
"model": "openai/gpt-4o",
"options": {}
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "c2aad759-3504-48e4-833a-771398ff586a",
"name": "Think",
"type": "@n8n/n8n-nodes-langchain.toolThink",
"position": [
224,
1744
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "89a37291-a019-488c-9ada-604f5460d638",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-1184,
912
],
"parameters": {
"color": 2,
"width": 960,
"height": 400,
"content": "## Get Chat Message / Audio Text\nDetect message type (/start, text, photo, file, audio) and route to the correct handler. \nText and audio messages are passed to the AI agent as-is.\n"
},
"typeVersion": 1
},
{
"id": "c245ce07-5c27-4096-8f16-85c3766a285d",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
-1136,
1024
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "start",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2061a135-7380-4108-b565-99ebc16ac37f",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Trigger').item.json.message.text }}",
"rightValue": "/start"
}
]
},
"renameOutput": true
},
{
"outputKey": "text",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "665a9274-2939-4069-ad27-02556447d7d3",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Trigger').item.json.message.text }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "audio",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d7360abd-5fce-4f60-832a-b7fb405255ee",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Trigger').item.json.message.voice.file_id }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "file",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "fa626c9d-b758-492b-ae44-fb6866763558",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Trigger').item.json.message.document.file_id }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "photo",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "194e3899-6a63-46db-a826-ad2768390ec5",
"operator": {
"type": "array",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Trigger').item.json.message.photo }}",
"rightValue": "photo"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.3
},
{
"id": "197310fd-2237-414a-84a0-ec7e2fada7b3",
"name": "TextOutput",
"type": "n8n-nodes-base.set",
"position": [
-592,
976
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
"name": "text",
"type": "string",
"value": "={{ $('Trigger').item.json.message.text }}"
},
{
"id": "65245fe2-4dd7-4330-974b-4a0fdbbd93a4",
"name": "chat_id",
"type": "string",
"value": "={{ $('Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ab6e3624-de0d-4043-ba72-3e62ee120d01",
"name": "WelcomeMessage",
"type": "n8n-nodes-base.telegram",
"position": [
-544,
736
],
"parameters": {
"text": "=Hi! I'm your personal expense tracker.\n\nSend me an expense in any format, and I'll save it automatically:\n- \ud83d\udcdd Text: \"spent 50 on groceries\"\n- \ud83d\udcf7 Receipt photo\n- \ud83d\udcc4 PDF invoice\n- \ud83c\udfa4 Voice: \"bought bread for 3 euros\"\n\nI'll organize everything by months and categories.\n\nAsk me anytime:\n- \"How much this month?\"\n- \"Show grocery expenses\"\n- \"Compare last 3 months\"\n\nReady to track your first expense?",
"chatId": "={{ $('Trigger').item.json.message.chat.id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "7c9b6743-39ec-4195-8792-dff233a859b1",
"name": "AudioOutput",
"type": "n8n-nodes-base.set",
"position": [
-592,
1136
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
"name": "text",
"type": "string",
"value": "={{ $json.content[0].text }}"
},
{
"id": "dde56955-afe3-4858-bc1b-bbca9a87ee65",
"name": "chat_id",
"type": "string",
"value": "={{ $('Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "35cd08cb-7dc2-4a5c-9454-47a9f9ce8dac",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
224,
912
],
"parameters": {
"color": 4,
"width": 288,
"height": 480,
"content": "## Result / Reply Message\nSends reply to the user"
},
"typeVersion": 1
},
{
"id": "c2ce80fa-f214-4dcc-a9bc-e182000d5125",
"name": "AgentInput",
"type": "n8n-nodes-base.set",
"position": [
-352,
1056
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "10b3fa10-e52d-4e80-b755-0c8310f391f3",
"name": "text",
"type": "string",
"value": "={{ $json.text }}"
},
{
"id": "72a11c20-6ba3-42a7-9a01-1a032f16e2c6",
"name": "chat_id",
"type": "string",
"value": "={{ $json.chat_id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "3db36880-18d1-408b-bcbf-a3578e471535",
"name": "NotAuthorizedMessage",
"type": "n8n-nodes-base.telegram",
"position": [
-1392,
1248
],
"parameters": {
"text": "=You are not authorized to use this bot.",
"chatId": "={{ $('Trigger').item.json.message.chat.id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "a4f01f8a-1317-4b4c-b447-e398702c6abf",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1760,
912
],
"parameters": {
"color": 2,
"width": 576,
"height": 496,
"content": "## Ensure Bot Privacy\nOn first use, the bot stores the user ID and locks access to that user. Any other user will receive an \u201cunauthorized\u201d message.\n"
},
"typeVersion": 1
},
{
"id": "17330fc2-6492-4e95-a07c-f7c6778ec66a",
"name": "IfAccessAllowed",
"type": "n8n-nodes-base.if",
"position": [
-1376,
1024
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "e3cd7b5c-eb77-451d-90a1-836353e32ab1",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $('Trigger').item.json.message.chat.id }}",
"rightValue": "={{ $json.chat_id ?? $('Trigger').item.json.message.chat.id }}"
},
{
"id": "61708b93-6439-4ef4-a08c-d997f6777033",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.error.status }}",
"rightValue": 404
}
]
}
},
"typeVersion": 2.2
},
{
"id": "4ef7ad67-59c1-4dce-87e5-098da8cbdccc",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-624,
656
],
"parameters": {
"color": 4,
"width": 400,
"height": 256,
"content": "## Start Message Reply\nSend user welcome message (first use)"
},
"typeVersion": 1
},
{
"id": "f883ad91-ce2b-4cca-a90d-901633cbba0f",
"name": "IfFirstRun",
"type": "n8n-nodes-base.if",
"position": [
-1712,
1504
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "61708b93-6439-4ef4-a08c-d997f6777033",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.error.status }}",
"rightValue": 404
}
]
}
},
"typeVersion": 2.2
},
{
"id": "7de993d2-81c0-4543-93b2-4d8453c608d1",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-1760,
1408
],
"parameters": {
"color": 4,
"width": 576,
"height": 288,
"content": "## First Run - Save Config\nOn first use remember user chat_id to enable authorization check in future"
},
"typeVersion": 1
},
{
"id": "7a9d43ec-7b81-4c8e-9222-6dd190645516",
"name": "ReplyText",
"type": "n8n-nodes-base.telegram",
"position": [
288,
1056
],
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('AgentInput').item.json.chat_id }}",
"additionalFields": {
"parse_mode": "Markdown",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "eaf63cad-d3a8-4e15-afcf-9a77e52b0b76",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-1184,
1312
],
"parameters": {
"color": 2,
"width": 960,
"height": 384,
"content": "## Get Document / Photo Text\nFor photo / file upload get file content and forward to agent with appropriate prefix to make it clear that content is coming from attached file.\n"
},
"typeVersion": 1
},
{
"id": "99cd1c7f-0e34-47f5-8245-91410420cf6a",
"name": "FileOutput",
"type": "n8n-nodes-base.set",
"position": [
-592,
1408
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
"name": "text",
"type": "string",
"value": "=User uploaded document / photo:\n\n{{ $('Input').item.json.message.caption ?? \"\" }}\n{{ $json.content ? $json.content[0].text : \"The uploaded file does not contain text content.\" }}"
},
{
"id": "dde56955-afe3-4858-bc1b-bbca9a87ee65",
"name": "chat_id",
"type": "string",
"value": "={{ $('Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a8d8281f-20d8-4039-9977-240372e8af46",
"name": "GetAudioFile",
"type": "n8n-nodes-base.telegram",
"position": [
-880,
1136
],
"parameters": {
"fileId": "={{ $('Trigger').item.json.message.voice.file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "ab30a917-2a51-4683-889a-dcb83b99e47d",
"name": "ExtractFileText",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-736,
1408
],
"parameters": {
"url": "https://api.ainoflow.io/api/v1/convert/submit-file",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "languages",
"value": "={{ $('Input').item.json.document_language }}"
},
{
"name": "outputs",
"value": "text"
},
{
"name": "response",
"value": "direct"
},
{
"name": "file",
"parameterType": "formBinaryData",
"inputDataFieldName": "data"
}
]
},
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "b7f8abf7-8a0a-4737-8ebf-bed1493b4cb1",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-224,
912
],
"parameters": {
"color": 5,
"width": 448,
"height": 480,
"content": "## Root Agent Processing\nMain agent responsible to forward messages to expense assistant, validate response, reject irrelevant topics, in future can be extended with more assistant connections"
},
"typeVersion": 1
},
{
"id": "a8a31b8b-09fc-4757-90ca-050d6ce6b90d",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-224,
1392
],
"parameters": {
"color": 5,
"width": 736,
"height": 560,
"content": "## Expense Assistant\nExpense assistant - handles the core logic about expenses, uses storage, calculator tools to process request"
},
"typeVersion": 1
},
{
"id": "3dd328b8-b601-4ff8-a3ee-aa09295aa872",
"name": "AssitantMemory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-48,
1744
],
"parameters": {
"sessionKey": "=expense_assitant_{{ $('AgentInput').item.json.chat_id }}",
"sessionIdType": "customKey"
},
"typeVersion": 1.3
},
{
"id": "0a183256-83ac-4e0c-9173-0affc14a6368",
"name": "SimpleMemory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-64,
1248
],
"parameters": {
"sessionKey": "=agent_{{ $('AgentInput').item.json.chat_id }}",
"sessionIdType": "customKey",
"contextWindowLength": 30
},
"typeVersion": 1.3
},
{
"id": "a304ae46-8c14-423b-8ebd-3ef4ad1156d6",
"name": "AIAgent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-160,
1056
],
"parameters": {
"text": "={{ $('AgentInput').item.json.text }}",
"options": {
"systemMessage": "=# Personal Expense Tracker\n\nYou DO NOT work with expenses directly. You call ExpenseAssistant for ALL expense requests.\n\n## Single Task\n\n1. Receive user message\n2. Pass to ExpenseAssistant WITHOUT modification\n3. Return its response\n\nCRITICAL: DO NOT extract amounts, do not reformat, do not summarize. Pass as-is.\n\n## When to Call ExpenseAssistant\n\nALWAYS call ExpenseAssistant for:\n- Any mention of spending, money, expenses\n- \"how much\", \"show\", \"expenses\"\n- ANY message starting with \"User uploaded document / photo:\" (regardless of content!)\n- Any text containing invoices, receipts, bills\n- Any numbers with currencies (EUR, USD, etc.)\n- Messages about \"does not contain text content\" or \"could not recognize\"\n\nCRITICAL: If you see \"User uploaded document / photo:\" \u2192 ALWAYS pass to ExpenseAssistant, even if there's an error!\n\n## For Non-Relevant Questions\n\n\"I'm an expense tracking assistant. I can add an expense or show statistics.\"\n\nDO NOT use this response for messages about uploaded documents!\n\n---\n\nCurrent date: {{ $now.toISO() }} \nMonth: {{ $now.toFormat('yyyy-MM') }} \nCurrency: EUR\n"
},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "528c64fe-cb38-40c0-b847-149ec391e413",
"name": "TranscribeAudio",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 2,
"position": [
-736,
1136
],
"parameters": {
"url": "https://api.ainoflow.io/api/v1/convert/submit-file",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "languages",
"value": "={{ $('Input').item.json.document_language }}"
},
{
"name": "outputs",
"value": "text"
},
{
"name": "response",
"value": "direct"
},
{
"name": "file",
"parameterType": "formBinaryData",
"inputDataFieldName": "data"
}
]
},
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "529f8d23-31c2-41d6-a721-a8a2760003c6",
"name": "Input",
"type": "n8n-nodes-base.set",
"position": [
-1728,
1024
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "3897ff73-577e-4e30-96bd-c043f3bc6c61",
"name": "document_language",
"type": "string",
"value": "={{ $json.message.from.language_code ?? \"en\" }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "f7a90943-7f8e-45e5-917c-0d2a8c5acc74",
"name": "GetAttachedFile",
"type": "n8n-nodes-base.telegram",
"position": [
-880,
1408
],
"parameters": {
"fileId": "={{ $('Trigger').item.json.message.document.file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "af85b4d7-23ee-44e8-9ae1-77c443808701",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-1184,
656
],
"parameters": {
"color": 4,
"width": 560,
"height": 256,
"content": "## Add processing started message\nNotify user about processing start (with message ... )"
},
"typeVersion": 1
},
{
"id": "3472eaa5-12ef-41c6-9562-2c430ebb0332",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-880,
1696
],
"parameters": {
"color": 4,
"width": 656,
"height": 256,
"content": "## Remove processing message\nAfter processing is complete, this part deletes temporary \"processing\" (\"...\") message"
},
"typeVersion": 1
},
{
"id": "3be5a7aa-b70e-4143-af04-cf0b3984ba36",
"name": "IfStateExist",
"type": "n8n-nodes-base.if",
"position": [
-624,
1792
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c5e9f88f-3726-43a4-9394-7b2b0a95b544",
"operator": {
"type": "number",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.chat_id }}",
"rightValue": ""
},
{
"id": "24d6e488-9735-49bb-af52-a84fcbfbde8c",
"operator": {
"type": "number",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.message_id }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "96232073-4006-42f3-b19b-9ce30853f1f9",
"name": "DeleteProcessing",
"type": "n8n-nodes-base.telegram",
"position": [
-384,
1792
],
"parameters": {
"chatId": "={{ $json.chat_id }}",
"messageId": "={{ $json.message_id }}",
"operation": "deleteMessage"
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "8d890581-cfe2-4b0e-b6ee-732978b0d697",
"name": "Think1",
"type": "@n8n/n8n-nodes-langchain.toolThink",
"position": [
48,
1248
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "aef6541d-fcde-49e8-80af-63f23509bdbe",
"name": "Cleanup",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1696,
1792
],
"parameters": {},
"typeVersion": 1
},
{
"id": "f57b4394-872c-44a0-96e9-c2990ec22447",
"name": "ForEachCategory",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-1504,
1792
],
"parameters": {
"url": "https://api.ainoflow.io/api/v1/storage/json",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "0077379d-2fda-451e-8b6c-1d8045d8c2db",
"name": "ForEachCategoryItem",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-1296,
1792
],
"parameters": {
"url": "=https://api.ainoflow.io/api/v1/storage/json/{{ $json.category }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "e09b5aa4-e64d-415b-8e18-f08aa005a98c",
"name": "DeleteItem",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-1072,
1792
],
"parameters": {
"url": "=https://api.ainoflow.io/api/v1/storage/json/{{ $json.category }}/{{ $json.key }}",
"method": "DELETE",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "73a49d7e-ae53-4dfb-863a-e696b1c95485",
"name": "GetAttachedPhoto",
"type": "n8n-nodes-base.telegram",
"position": [
-880,
1536
],
"parameters": {
"fileId": "={{ $('Trigger').item.json.message.photo[$('Trigger').item.json.message.photo.length-1].file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "a1fc3d64-ddf8-402c-b60f-a9e022f2f17d",
"name": "ImageOutput",
"type": "n8n-nodes-base.set",
"position": [
-592,
1536
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
"name": "text",
"type": "string",
"value": "=User uploaded document / photo:\n\n{{ $('Input').item.json.message.caption ?? \"\" }}\n{{ $json.content ? $json.content[0].text : \"The uploaded file does not contain text content.\" }}"
},
{
"id": "dde56955-afe3-4858-bc1b-bbca9a87ee65",
"name": "chat_id",
"type": "string",
"value": "={{ $('Trigger').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9e7fa633-a3d5-4de1-b8b7-f056090069bf",
"name": "Sticky Note12",
"type": "n8n-nodes-base.stickyNote",
"disabled": true,
"position": [
-1760,
1696
],
"parameters": {
"color": 7,
"width": 880,
"height": 256,
"content": "## Cleanup / Reset\nThis is **MANUAL** trigger to full data cleanup. **Warning - this will DELETE ALL DATA** stored in your **Ainoflow** account"
},
"typeVersion": 1
},
{
"id": "424964de-61df-4f24-97a4-ae6f5d74b478",
"name": "ExtractImageText",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-736,
1536
],
"parameters": {
"url": "https://api.ainoflow.io/api/v1/convert/submit-file",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "languages",
"value": "={{ $('Input').item.json.document_language }}"
},
{
"name": "outputs",
"value": "text"
},
{
"name": "response",
"value": "direct"
},
{
"name": "file",
"parameterType": "formBinaryData",
"inputDataFieldName": "data"
},
{
"name": "models",
"value": "paddleocr"
}
]
},
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "8272ec82-344c-4769-91ac-ccebce125777",
"name": "SendProcessing",
"type": "n8n-nodes-base.telegram",
"position": [
-1104,
752
],
"parameters": {
"text": "=...",
"chatId": "={{ $('Trigger').item.json.message.chat.id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "90dc3683-4e85-4c79-a44d-52f04e2d6e39",
"name": "GetExecutionState",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-816,
1792
],
"parameters": {
"url": "=https://api.ainoflow.io/api/v1/storage/json/expense-app-processing/{{ $('Trigger').item.json.update_id }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "bf8eec4b-64b7-4580-840b-f2d910e949b7",
"name": "Sonnet45",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
-176,
1744
],
"parameters": {
"model": "anthropic/claude-sonnet-4.5",
"options": {}
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "9cd45908-6cb1-499a-9e8c-95f4cc69e4e5",
"name": "GetAppSettings",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-1552,
1024
],
"parameters": {
"url": "https://api.ainoflow.io/api/v1/storage/json/config/expense-app-settings",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "a5ed9d9e-8fb1-4fba-8537-d4fe91932517",
"name": "SaveAppSettings",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1488,
1488
],
"parameters": {
"url": "https://api.ainoflow.io/api/v1/storage/json/config/expense-app-settings",
"method": "PUT",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "={{ $('Trigger').item.json.message.chat.id }}"
},
{
"name": "start_date",
"value": "={{ $('Trigger').item.json.message.date }}"
},
{
"name": "first_name",
"value": "={{ $('Trigger').item.json.message.chat.first_name }}"
}
]
},
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "e6b007bf-589a-46b4-ae5e-0f0ae88bcd17",
"name": "SaveExecutionState",
"type": "n8n-nodes-base.httpRequest",
"position": [
-912,
752
],
"parameters": {
"url": "=https://api.ainoflow.io/api/v1/storage/json/expense-app-processing/{{ $('Trigger').item.json.update_id }}",
"method": "PUT",
"options": {},
"sendBody": true,
"sendQuery": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "={{ $json.result.chat.id }}"
},
{
"name": "message_id",
"value": "={{ $json.result.message_id }}"
}
]
},
"genericAuthType": "httpBearerAuth",
"queryParameters": {
"parameters": [
{
"name": "expiresMs",
"value": "3600000"
}
]
}
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "50b5551e-ef7d-4590-81d0-37339c1a8794",
"connections": {
"Gpt4o": {
"ai_languageModel": [
[
{
"node": "AIAgent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Input": {
"main": [
[
{
"node": "GetAppSettings",
"type": "main",
"index": 0
}
]
]
},
"Think": {
"ai_tool": [
[
{
"node": "ExpenseAssistant",
"type": "ai_tool",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "WelcomeMessage",
"type": "main",
"index": 0
}
],
[
{
"node": "TextOutput",
"type": "main",
"index": 0
}
],
[
{
"node": "GetAudioFile",
"type": "main",
"index": 0
}
],
[
{
"node": "GetAttachedFile",
"type": "main",
"index": 0
}
],
[
{
"node": "GetAttachedPhoto",
"type": "main",
"index": 0
}
]
]
},
"Think1": {
"ai_tool": [
[
{
"node": "AIAgent",
"type": "ai_tool",
"index": 0
}
]
]
},
"AIAgent": {
"main": [
[
{
"node": "ReplyText",
"type": "main",
"index": 0
}
]
]
},
"Cleanup": {
"main": [
[
{
"node": "ForEachCategory",
"type": "main",
"index": 0
}
]
]
},
"Trigger": {
"main": [
[
{
"node": "Input",
"type": "main",
"index": 0
}
]
]
},
"Sonnet45": {
"ai_languageModel": [
[
{
"node": "ExpenseAssistant",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AgentInput": {
"main": [
[
{
"node": "AIAgent",
"type": "main",
"index": 0
}
]
]
},
"Calculator": {
"ai_tool": [
[
{
"node": "ExpenseAssistant",
"type": "ai_tool",
"index": 0
}
]
]
},
"FileOutput": {
"main": [
[
{
"node": "AgentInput",
"type": "main",
"index": 0
}
]
]
},
"IfFirstRun": {
"main": [
[
{
"node": "SaveAppSettings",
"type": "main",
"index": 0
}
]
]
},
"TextOutput": {
"main": [
[
{
"node": "AgentInput",
"type": "main",
"index": 0
}
]
]
},
"AudioOutput": {
"main": [
[
{
"node": "AgentInput",
"type": "main",
"index": 0
}
]
]
},
"ImageOutput": {
"main": [
[
{
"node": "AgentInput",
"type": "main",
"index": 0
}
]
]
},
"GetAudioFile": {
"main": [
[
{
"node": "TranscribeAudio",
"type": "main",
"index": 0
}
]
]
},
"IfStateExist": {
"main": [
[
{
"node": "DeleteProcessing",
"type": "main",
"index": 0
}
]
]
},
"SimpleMemory": {
"ai_memory": [
[
{
"node": "AIAgent",
"type": "ai_memory",
"index": 0
}
]
]
},
"AssitantMemory": {
"ai_memory": [
[
{
"node": "ExpenseAssistant",
"type": "ai_memory",
"index": 0
}
]
]
},
"GetAppSettings": {
"main": [
[
{
"node": "IfFirstRun",
"type": "main",
"index": 0
},
{
"node": "IfAccessAllowed",
"type": "main",
"index": 0
}
]
]
},
"JsonStorageMcp": {
"ai_tool": [
[
{
"node": "ExpenseAssistant",
"type": "ai_tool",
"index": 0
}
]
]
},
"SendProcessing": {
"main": [
[
{
"node": "SaveExecutionState",
"type": "main",
"index": 0
}
]
]
},
"ExtractFileText": {
"main": [
[
{
"node": "FileOutput",
"type": "main",
"index": 0
}
]
]
},
"ForEachCategory": {
"main": [
[
{
"node": "ForEachCategoryItem",
"type": "main",
"index": 0
}
]
]
},
"GetAttachedFile": {
"main": [
[
{
"node": "ExtractFileText",
"type": "main",
"index": 0
}
]
]
},
"IfAccessAllowed": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
},
{
"node": "SendProcessing",
"type": "main",
"index": 0
},
{
"node": "GetExecutionState",
"type": "main",
"index": 0
}
],
[
{
"node": "NotAuthorizedMessage",
"type": "main",
"index": 0
}
]
]
},
"TranscribeAudio": {
"main": [
[
{
"node": "AudioOutput",
"type": "main",
"index": 0
}
]
]
},
"ExpenseAssistant": {
"ai_tool": [
[
{
"node": "AIAgent",
"type": "ai_tool",
"index": 0
}
]
]
},
"ExtractImageText": {
"main": [
[
{
"node": "ImageOutput",
"type": "main",
"index": 0
}
]
]
},
"GetAttachedPhoto": {
"main": [
[
{
"node": "ExtractImageText",
"type": "main",
"index": 0
}
]
]
},
"GetExecutionState": {
"main": [
[
{
"node": "IfStateExist",
"type": "main",
"index": 0
}
]
]
},
"ForEachCategoryItem": {
"main": [
[
{
"node": "DeleteItem",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpBearerAuthopenRouterApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AI-powered Telegram bot for effortless expense tracking. Send receipts, voice messages, or text - the bot automatically extracts and categorizes your expenses. 📸 Receipt & Invoice OCR - Send photos of receipts or PDF invoices, AI extracts expense data automatically 🎤 Voice…
Source: https://n8n.io/workflows/11368/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
The AI-Powered Shopify SEO Content Automation is an enterprise-grade workflow that transforms product content creation for e-commerce stores. This sophisticated multi-agent system integrates GPT-4o, C
Creators, marketers, and brands that want to turn a single product photo into premium motion clips, then optionally publish to Instagram/TikTok/YouTube via LATE. No editing skills required.
Product to Social Video (xCodeWraith Edition). Uses telegram, agentTool, telegramTrigger, httpRequest. Event-driven trigger; 83 nodes.
Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.
Transform your salon/service business with this streamlined Telegram automation system featuring Claude integration, zero-setup database management, and intelligent conversation handling. Claude MCP I