This workflow corresponds to n8n.io template #10993 — we link there as the canonical source.
This workflow follows the Chainllm → Google Sheets 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": "Snt5iPZg9K6OAymZ",
"meta": {
"templateId": "voice_assistant_agent_with_telegram",
"templateCredsSetupCompleted": true
},
"name": "Expense Tracker Workflow Template",
"tags": [],
"nodes": [
{
"id": "d71544a0-04a0-4a73-b0d9-e4db8852dc19",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
240,
224
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "c7f116d1-f52e-460c-ab58-1e5b44827491",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
432,
208
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"Date\",\"Category\",\"Amount\"],\n \"properties\": {\n \"Date\": { \"type\":\"string\", \"pattern\":\"^\\\\d{4}-\\\\d{2}-\\\\d{2}$\" },\n \"Category\": { \"type\":\"string\" },\n \"Merchant\": { \"type\":[\"string\",\"null\"] },\n \"Amount\": { \"type\":\"number\" },\n \"Note\": { \"type\":[\"string\",\"null\"] }\n },\n \"additionalProperties\": false\n }\n}\n"
},
"typeVersion": 1.3
},
{
"id": "ead09816-98d8-442f-af2a-24ec186f4279",
"name": "Parse Expenses with AI",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
224,
0
],
"parameters": {
"text": "=You are Expense Parser. Your job is to read a message describing one or more expenses and return ONLY a valid JSON array of objects for a Google Sheet with columns: Date, Category, Merchant, Amount, Note.\n\nEach object must look like:\n{\n \"Date\": \"YYYY-MM-DD\",\n \"Category\": \"Food & Drink\" | \"Entertainment\" | \"Groceries\" | \"Transport\" | \"Fuel\" | \"Rent\" | \"Health\" | \"Shopping\" | \"Travel\" | \"Utilities\" | \"Income\" | \"Other\",\n \"Merchant\": \"string or null\",\n \"Amount\": number,\n \"Note\": \"string or null\"\n}\n\nRules:\n- Date = today if not given (use {{ $now.toFormat('yyyy-MM-dd') }}).\n- Amount: numbers only (strip $ or commas).\n- Category: infer best match or \"Other\".\n- Merchant: short name if mentioned.\n- Note: short context like \"Lunch\", \"Gas\", \"Movie tickets\".\nIf no valid expenses, return [].\n\nOutput MUST be ONLY a JSON array matching the schema. No prose or code fences\nUser message: {{ $('Telegram Message Trigger').item.json.message.text }}\nAudio User Message: {{ $json.text }}",
"batching": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "ba58f8fa-7bba-4eb4-9276-e29bbd0a9135",
"name": "Append to Google Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1056,
16
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $json.Date }}",
"Note": "={{ $json.Note }}",
"Amount": "={{ $json.Amount }}",
"Category": "={{ $json.Category }}",
"Merchant": "={{ $json.Merchant }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Category",
"type": "string",
"display": true,
"required": false,
"displayName": "Category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Merchant",
"type": "string",
"display": true,
"required": false,
"displayName": "Merchant",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Amount",
"type": "string",
"display": true,
"required": false,
"displayName": "Amount",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Note",
"type": "string",
"display": true,
"required": false,
"displayName": "Note",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Date"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1008795218,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/18hPbBmXjcs7Vqi2JN5b6xD-GDjMhVVedbpLitKTXHdo/edit#gid=1008795218",
"cachedResultName": "Expenses"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "18hPbBmXjcs7Vqi2JN5b6xD-GDjMhVVedbpLitKTXHdo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/18hPbBmXjcs7Vqi2JN5b6xD-GDjMhVVedbpLitKTXHdo/edit?usp=drivesdk",
"cachedResultName": "Expense Tracker"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "d65ced97-b390-4c65-9f0c-d62100c27abd",
"name": "Wait 0.5 seconds",
"type": "n8n-nodes-base.wait",
"position": [
1264,
16
],
"parameters": {
"amount": 0.5
},
"typeVersion": 1.1
},
{
"id": "b4b6cd46-e379-4384-9a9c-84a133258a0c",
"name": "Send Telegram Confirmation",
"type": "n8n-nodes-base.telegram",
"position": [
1968,
-32
],
"parameters": {
"text": "={{ $json.text }}",
"chatId": "={{ $('Telegram Message Trigger').first().json.message.chat.id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "a53bba6f-067f-4f5a-8ecb-43c13b1cbe10",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
576,
0
],
"parameters": {
"options": {},
"fieldToSplitOut": "output"
},
"typeVersion": 1
},
{
"id": "bebffb6b-fba5-4cc1-b2fc-d2e411a0322b",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
848,
0
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "f96ba471-26c0-49d7-a598-75c7250970c7",
"name": "Telegram Message Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-928,
16
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {
"download": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "93c9787e-0762-4353-acc7-ad1af68c1ad6",
"name": "Check if Audio file",
"type": "n8n-nodes-base.if",
"position": [
-704,
16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2b538077-d3d3-4713-b973-68748313ff97",
"operator": {
"type": "object",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.message.voice }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1e00fabd-b1f6-47b9-9ea6-98752e8606b7",
"name": "Transcribe audio",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-256,
-80
],
"parameters": {
"options": {},
"resource": "audio",
"operation": "transcribe"
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.8
},
{
"id": "d79a073d-16b5-47c3-a5c2-309467909892",
"name": "Set field",
"type": "n8n-nodes-base.set",
"position": [
-256,
112
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "eb912219-2436-4f04-8ffc-c1c20eb07344",
"name": "text",
"type": "string",
"value": "={{ $json.message.text }}"
},
{
"id": "ded90f7a-bd44-4648-a9eb-5c16d2356adb",
"name": "",
"type": "string",
"value": ""
}
]
}
},
"typeVersion": 3.4
},
{
"id": "789e3937-56ae-4184-9bff-756e28e8a49d",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
1456,
-32
],
"parameters": {
"mode": "chooseBranch"
},
"typeVersion": 3.2
},
{
"id": "7b9b778b-67ed-4f7b-a9cd-ce3a99187512",
"name": "Get File",
"type": "n8n-nodes-base.telegram",
"position": [
-480,
-80
],
"parameters": {
"fileId": "={{ $json.message.voice.file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "7a049246-8692-4ca2-92d7-6044ce0f5fe8",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1088,
-624
],
"parameters": {
"color": 3,
"width": 416,
"height": 208,
"content": "### \ud83d\udee0\ufe0f Troubleshooting \n- **Missing rows?** Increase the Wait time to 800\u20131200 ms. \n- **AI returns no expenses?** Check that your message includes numbers and merchants. \n- **Google Sheets errors?** Confirm spreadsheet ID, sheet name, and column mapping. \n- **Audio not transcribing?** Ensure Whisper is selected in the transcription node.\n"
},
"typeVersion": 1
},
{
"id": "cec5f58e-0599-4885-ad84-3c5fc2a136e5",
"name": "Build Expense Summary Text",
"type": "n8n-nodes-base.code",
"position": [
864,
-160
],
"parameters": {
"jsCode": "// Build one message from all Split Out items\nconst items = $input.all().map(i => i.json);\nconst lines = items.map(e =>\n `${e.Date} \u2014 ${e.Category} $${Number(e.Amount).toFixed(2)}${e.Merchant ? ' ('+e.Merchant+')' : ''}`\n);\nconst count = items.length;\nreturn [{\n json: {\n text: `Just tracked ${count} expense${count!==1?'s':''}:\\n` + lines.join('\\n')\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "e63af906-3ac2-4b91-a528-aa82b3bc0a21",
"name": "Build Confirmation Text",
"type": "n8n-nodes-base.set",
"position": [
1664,
-32
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a029bf2c-7ba9-4114-a679-bc68f04f7030",
"name": "text",
"type": "string",
"value": "={{ $json.text }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "3bae6da9-7466-4b8d-99bc-40ff66f37441",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1760,
0
],
"parameters": {
"width": 672,
"height": 288,
"content": "### \ud83d\udd27 Setup Instructions \n1. Connect credentials: **Telegram**, **Google**, **OpenAI**. \n2. Create a Google Sheet with headers: \n `Date | Category | Merchant | Amount | Note` \n3. Copy your Sheet ID + Sheet name. \n4. Map the columns correctly in the **Append to Google Sheet** node. \n5. Pick models: \n - Chat model: `gpt-4o-mini` (recommended) \n - Audio transcription: Whisper (for voice notes) \n6. Keep the **Wait** node at `500\u20131000 ms` to avoid API race conditions. \n7. Test by sending a message like: \n `Gas 34.67, Groceries 82.45, Coffee 6.25, Lunch 14.90`\n"
},
"typeVersion": 1
},
{
"id": "e9678959-c7f9-4cff-9f29-065fee86fc6a",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1760,
-624
],
"parameters": {
"width": 672,
"height": 624,
"content": "### \ud83d\udccc Purpose \nLog multiple expenses directly from Telegram into Google Sheets \u2014 using either text or audio messages.\n\nThis workflow is for anyone who wants a **fast, low-effort way to track expenses** without opening a spreadsheet or app. You simply send a quick message (or voice note) like:\n\n`Groceries 82.45, Coffee 6.25, Uber 14.90`\n\nand each item is automatically parsed and saved as its own row.\n\n**Who this helps:** \n- Busy entrepreneurs \n- Freelancers and contractors \n- People who track business expenses manually \n- Anyone who prefers capturing expenses on the go \n- Users who don\u2019t want to build a full accounting system\n\n**Why this is useful:** \n- It replaces the repetitive task of entering expenses manually \n- Voice notes let you log hands-free while driving or moving \n- AI extracts multiple expenses from a single message, saving time \n- Google Sheets keeps your data accessible, editable, and exportable \n- Works instantly from your phone through Telegram\n\n**Why download this template:** \nIt gives you a ready-made, reliable system for expense tracking with **zero manual data entry**, using AI and simple messaging. No accounting software needed \u2014 just Telegram and a Google Sheet.\n\n"
},
"typeVersion": 1
},
{
"id": "0f45caec-6049-4a2b-bf3a-ff39cc305fc8",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
-288
],
"parameters": {
"color": 7,
"width": 960,
"height": 608,
"content": "### \ud83c\udfa4 Telegram Input & Transcription \nThis section receives a Telegram message, detects if it's audio, and transcribes it when needed.\n\nWhy: We want the user to be able to log expenses hands-free through **text or voice**, so both inputs flow into the same text-processing path.\n"
},
"typeVersion": 1
},
{
"id": "d25f9ad8-c964-4c49-a02e-d92316937094",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
-288
],
"parameters": {
"color": 7,
"width": 624,
"height": 640,
"content": "### \ud83e\udd16 AI Parsing & Expense Extraction \nThis section uses AI to identify all expenses in the message, splits them into individual items, and prepares them for Google Sheets.\n\nWhy: A single message may contain several expenses \u2014 AI helps extract structured fields reliably.\n"
},
"typeVersion": 1
},
{
"id": "205d3995-05cd-491b-a9b6-3c7d7229e12f",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
784,
-336
],
"parameters": {
"color": 7,
"width": 1408,
"height": 688,
"content": "### \ud83d\udcca Write to Sheets & Send Confirmation \nThis section loops through each expense, writes it to Google Sheets, builds a summary, and sends a confirmation back to Telegram.\n\nWhy: Users need quick feedback that everything was recorded correctly.\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "8becffad-c320-4615-b121-563074fa866d",
"connections": {
"Merge": {
"main": [
[
{
"node": "Build Confirmation Text",
"type": "main",
"index": 0
}
]
]
},
"Get File": {
"main": [
[
{
"node": "Transcribe audio",
"type": "main",
"index": 0
}
]
]
},
"Set field": {
"main": [
[
{
"node": "Parse Expenses with AI",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
},
{
"node": "Build Expense Summary Text",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
],
[
{
"node": "Append to Google Sheet",
"type": "main",
"index": 0
}
]
]
},
"Transcribe audio": {
"main": [
[
{
"node": "Parse Expenses with AI",
"type": "main",
"index": 0
}
]
]
},
"Wait 0.5 seconds": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Parse Expenses with AI",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Check if Audio file": {
"main": [
[
{
"node": "Get File",
"type": "main",
"index": 0
}
],
[
{
"node": "Set field",
"type": "main",
"index": 0
}
]
]
},
"Append to Google Sheet": {
"main": [
[
{
"node": "Wait 0.5 seconds",
"type": "main",
"index": 0
}
]
]
},
"Parse Expenses with AI": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Build Confirmation Text": {
"main": [
[
{
"node": "Send Telegram Confirmation",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Parse Expenses with AI",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Telegram Message Trigger": {
"main": [
[
{
"node": "Check if Audio file",
"type": "main",
"index": 0
}
]
]
},
"Build Expense Summary Text": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Send Telegram Confirmation": {
"main": [
[]
]
}
}
}
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.
googleSheetsOAuth2ApiopenAiApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
-Personal or family budget tracking.
Source: https://n8n.io/workflows/10993/ — 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.
Generate AI viral videos with NanoBanana & VEO3, shared on socials via Blotato 2. Uses @blotato/n8n-nodes-blotato, googleSheets, lmChatOpenAi, toolThink. Event-driven trigger; 94 nodes.
This template is designed for marketers, content creators, and e-commerce brands who want to automate the creation of professional ad videos at scale. It’s ideal for teams looking to generate consiste
This automation is designed to help you generate AI-powered music tracks, cover art, and fully rendered music videos — all triggered from a simple Telegram chat and managed via Google Sheets.
Automatically capture, categorize, and log expenses from receipts, PDFs, voice notes, or text — powered by AI and integrated with Telegram and Google Sheets.
Create Video Ia. Uses @blotato/n8n-nodes-blotato, googleSheets, lmChatOpenAi, toolThink. Event-driven trigger; 47 nodes.