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
💥 Automate video ads with NanoBanana, Seedream 4, ChatGPT Image and Veo 3 - VIDE. Uses telegram, telegramTrigger, googleDrive, agent. Event-driven trigger; 63 nodes.
💥 Automate video ads with NanoBanana, Seedream 4, ChatGPT Image and Veo 3 - VIDE. Uses telegram, telegramTrigger, googleDrive, agent. Event-driven trigger; 63 nodes.
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.