AutomationFlows β€Ί AI & RAG β€Ί Automatic Expense Tracking with Telegram, Ai, and Google Sheets

Automatic Expense Tracking with Telegram, Ai, and Google Sheets

ByM Sayed @msayed-csβœ“ on n8n.io

The Problem 😫 Tired of manually logging every coffee and cab ride? Stop wrestling with spreadsheets! This template automates your expense tracking so you can manage your finances effortlessly.

Event triggerβ˜…β˜…β˜…β˜…β˜† complexityAI-powered10 nodesTelegram TriggerAgentOpenAI ChatAnthropic ChatHTTP Request ToolOutput Parser StructuredGoogle SheetsGoogle Gemini Chat
AI & RAG Trigger: Event Nodes: 10 Complexity: β˜…β˜…β˜…β˜…β˜† AI nodes: yes Added:

This workflow corresponds to n8n.io template #6210 β€” we link there as the canonical source.

This workflow follows the Agent β†’ 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 β†’

Download .json
{
  "id": "B1P6d8Jusl69JubP",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "MS_SPEND_TRACKER",
  "tags": [],
  "nodes": [
    {
      "id": "76519239-54b1-40e3-b7df-5c86c006a893",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -100,
        0
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {
          "chatIds": "={{ $env.chat_id }}",
          "download": true
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "60fedb80-ee63-4a46-916c-9d133b9fa874",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        220,
        0
      ],
      "parameters": {
        "text": "===Parse this expense message and extract structured spending.\n\nMESSAGE: \"{{ $json.message?.text || $json.chatInput }}\"\nFROM USER: {{ $json.message?.from.id || 1 }}\nTIMESTAMP: {{ $now }}\n\n**INSTRUCTIONS:**\n1. **Parse the message** to extract the amount, description, currency, and payment method.\n2. **Currency & Exchange Rate Logic:**\n   * Identify the currency from the message (EGP, USD, SAR, AED). If no currency is mentioned, default to \"EGP\".\n   * **CRITICAL:** Only use the `Get Rates` tool if the identified currency is USD, SAR, or AED.\n   * If the currency is \"EGP\", set the `exchange_rate` to `1` and the `amount_converted` to be the same as the `amount`. Do NOT use the `Get Rates` tool for EGP transactions.\n3. **Categorization:** Assign a category based on the `CATEGORY MAPPING HINTS`. If no clear category fits, use \"Other\".\n4. **Final Output:** Respond with ONLY a valid JSON object. No explanations, no markdown formatting.\n\n---\n**CATEGORY MAPPING HINTS:**\n- \"coffee\", \"caf\u00e9\", \"starbucks\" \u2192 Coffee\n- \"uber\", \"taxi\", \"metro\", \"bus\" \u2192 Transport\n- \"supermarket\", \"carrefour\", \"spinneys\" \u2192 Groceries\n- \"restaurant\", \"food\", \"lunch\", \"dinner\" \u2192 Food & Dining\n- \"clothes\", \"shoes\", \"mall\" \u2192 Shopping\n- \"medicine\", \"doctor\", \"pharmacy\" \u2192 Health\n- \"netflix\", \"spotify\", \"gym\" \u2192 Subscriptions\n\n**PAYMENT METHOD HINTS:**\n- \"cash\", \"\u0646\u0642\u062f\u064a\" \u2192 Cash (default)\n- \"card\", \"visa\", \"mastercard\" \u2192 Credit Card\n- \"vodafone cash\", \"wallet\" \u2192 Wallet\n- \"transfer\", \"bank\" \u2192 Bank Transfer\n\n---\n\n**REQUIRED OUTPUT FORMAT:**\n{\n  \"amount\": <number>,\n  \"category\": \"<string>\",\n  \"description\": \"<string>\",\n  \"date\": \"<ISO date-time string>\",\n  \"user_id\": \"<string>\",\n  \"payment_method\": \"<string>\",\n  \"currency\": \"<string>\",\n  \"exchange_rate\": <number>,\n  \"amount_converted\": <number>\n}",
        "options": {
          "systemMessage": "You are a financial data extraction specialist. You receive natural language text about expenses and convert them to structured JSON.\n\nCRITICAL RULES:\n1. Always return valid JSON only - no explanations, no markdown\n2. All required fields must be present\n3. Numbers must be actual numbers, not strings\n4. Dates must be in ISO format\n5. If information is missing, use sensible defaults\n\nYou must follow the exact JSON schema provided in the user prompt."
        },
        "promptType": "define",
        "needsFallback": true,
        "hasOutputParser": true
      },
      "typeVersion": 2
    },
    {
      "id": "f7bb1c22-e64a-4a15-b483-823bb8c56ceb",
      "name": "o3",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        260,
        280
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "o3",
          "cachedResultName": "o3"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3867cd64-89a1-49c5-a81b-046970cea171",
      "name": "H3.5",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        40,
        280
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-3-5-haiku-20241022",
          "cachedResultName": "Claude Haiku 3.5"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "6ffd9ec9-2e7a-4a96-8ed7-4dd6dd60dd76",
      "name": "Get Rates",
      "type": "n8n-nodes-base.httpRequestTool",
      "position": [
        500,
        280
      ],
      "parameters": {
        "url": "https://open.er-api.com/v6/latest/EGP",
        "options": {},
        "toolDescription": "Get exchange rates for EGP"
      },
      "typeVersion": 4.2
    },
    {
      "id": "5e9fd301-a6c2-4e5f-8eda-46d4f20475e9",
      "name": "Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        620,
        280
      ],
      "parameters": {
        "autoFix": true,
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"amount\": {\n      \"type\": \"number\",\n      \"description\": \"The expense amount in the original currency\"\n    },\n    \"category\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Groceries\",\n        \"Transport\", \n        \"Food & Dining\",\n        \"Shopping\",\n        \"Personal Care\",\n        \"Health\",\n        \"Utilities\",\n        \"Entertainment\",\n        \"Education\",\n        \"Bills\",\n        \"Subscriptions\",\n        \"Donations\",\n        \"Family\",\n        \"Other\"\n      ],\n      \"description\": \"The expense category from predefined list\"\n    },\n    \"description\": {\n      \"type\": \"string\",\n      \"description\": \"Description or note about the expense\"\n    },\n    \"date\": {\n      \"type\": \"string\",\n      \"format\": \"date-time\",\n      \"description\": \"ISO 8601 date-time string of when the expense occurred\"\n    },\n    \"user_id\": {\n      \"type\": \"string\",\n      \"description\": \"Telegram user ID who made the expense\"\n    },\n    \"payment_method\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Cash\",\n        \"Credit Card\", \n        \"Wallet\"\n      ],\n      \"description\": \"Method used to make the payment\"\n    },\n    \"currency\": {\n      \"type\": \"string\",\n      \"enum\": [\"EGP\", \"USD\", \"SAR\", \"AED\"],\n      \"description\": \"Original currency of the transaction\"\n    },\n    \"exchange_rate\": {\n      \"type\": \"number\",\n      \"description\": \"Exchange rate from original currency to EGP (1.0 if already EGP)\"\n    },\n    \"amount_converted\": {\n      \"type\": \"number\", \n      \"description\": \"Amount converted to EGP using the exchange rate\"\n    }\n  },\n  \"required\": [\n    \"amount\",\n    \"category\", \n    \"description\",\n    \"date\",\n    \"user_id\",\n    \"payment_method\",\n    \"currency\",\n    \"exchange_rate\",\n    \"amount_converted\"\n  ],\n  \"additionalProperties\": false\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "8b0131e6-7cb1-4445-8785-6c938499a132",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        860,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $json.date }}",
            "amount": "={{ $json.amount }}",
            "user_id": "={{ $json.user_id }}",
            "category": "={{ $json.category }}",
            "currency": "={{ $json.currency }}",
            "description": "={{ $json.description }}",
            "exchange_rate": "={{ $json.exchange_rate }}",
            "payment_method": "={{ $json.payment_method }}",
            "amount_converted": "={{ $json.amount_converted }}"
          },
          "schema": [
            {
              "id": "amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "user_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "user_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "payment_method",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "payment_method",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "exchange_rate",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "exchange_rate",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "amount_converted",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "amount_converted",
              "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/1v5ffTb0q-kS4yE6ItklO-L1CX3qKVgIT1VlGK2pEU6s/edit#gid=0",
          "cachedResultName": "txn"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1v5ffTb0q-kS4yE6ItklO-L1CX3qKVgIT1VlGK2pEU6s",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1v5ffTb0q-kS4yE6ItklO-L1CX3qKVgIT1VlGK2pEU6s/edit?usp=drivesdk",
          "cachedResultName": "n8n-spending-tracker"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "62b68b7f-1bf0-44e2-8596-87fd6af48fdb",
      "name": "2.5F",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -60,
        280
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "688170f6-31f9-495b-a617-fc84c142569b",
      "name": "2.5F1",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        620,
        440
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c9250987-9160-49b6-9d8a-00865065487e",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        0
      ],
      "parameters": {
        "jsCode": "// Process AI Agent output and fix date format for Google Sheets\nconst aiOutput = $input.first().json.output;\n\n// Convert ISO date to Google Sheets compatible format\nfunction formatDateForSheets(isoString) {\n  const date = new Date(isoString);\n  // Format as YYYY-MM-DD HH:MM:SS (Google Sheets preferred format)\n  return date.toISOString().slice(0, 19).replace('T', ' ');\n}\n\n// Process the data with proper date formatting\nconst processedData = {\n  amount: Number(aiOutput.amount) || 0,\n  category: String(aiOutput.category || 'Other'),\n  description: String(aiOutput.description || ''),\n  date: formatDateForSheets(aiOutput.date || new Date().toISOString()),\n  user_id: String(aiOutput.user_id || ''),\n  payment_method: String(aiOutput.payment_method || 'Other'),\n  currency: String(aiOutput.currency || 'EGP'),\n  exchange_rate: Number(aiOutput.exchange_rate) || 1,\n  amount_converted: Number(aiOutput.amount_converted) || Number(aiOutput.amount) || 0\n};\n\nreturn [{ json: processedData }];"
      },
      "typeVersion": 2
    }
  ],
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "49657870-ce61-456e-ad93-d2be3e50012b",
  "connections": {
    "o3": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "2.5F": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "H3.5": {
      "ai_languageModel": [
        []
      ]
    },
    "2.5F1": {
      "ai_languageModel": [
        [
          {
            "node": "Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Rates": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "AI Agent",
            "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.

Pro

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

About this workflow

The Problem 😫 Tired of manually logging every coffee and cab ride? Stop wrestling with spreadsheets! This template automates your expense tracking so you can manage your finances effortlessly.

Source: https://n8n.io/workflows/6210/ β€” original creator credit. Request a take-down β†’

More AI & RAG workflows β†’ Β· Browse all categories β†’

Related workflows

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

AI & RAG

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.

OpenAI Chat, Memory Buffer Window, Output Parser Structured +11
AI & RAG

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Output Parser Structured, Telegram, N8N Nodes Tesseractjs +14
AI & RAG

This workflow automates Facebook posting and appointment booking directly from a Telegram bot, making it especially useful for pet grooming businesses that want to keep their social media active while

Google Sheets, OpenAI Chat, Output Parser Structured +12
AI & RAG

πŸš€ Smart Outreach: Auto-Personalized Lead Sequences

Telegram Trigger, Agent, OpenAI Chat +6
AI & RAG

Bot - telegram - Clima. Uses telegramTrigger, agent, lmChatOpenAi, outputParserStructured. Event-driven trigger; 21 nodes.

Telegram Trigger, Agent, OpenAI Chat +7