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 →
{
"nodes": [
{
"parameters": {
"content": "**1. Trigger**\nReceives photo message from Telegram bot and downloads the image file",
"height": 228,
"width": 264
},
"id": "0325534b-b937-4cf5-b361-c7193ab239c0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
2336
],
"typeVersion": 1
},
{
"parameters": {
"content": "**2. OCR Processing**\nGemini Vision extracts all visible text from the invoice image",
"height": 80,
"width": 260
},
"id": "22222a5e-b863-4f15-b8b0-ecc08b00d18e",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
336,
2336
],
"typeVersion": 1
},
{
"parameters": {
"content": "**3. Data Extraction**\nLLM parses OCR text into structured JSON with standard invoice fields",
"height": 80,
"width": 300
},
"id": "4f18f88f-ee17-48a8-a1ae-c934f807e1e2",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-384,
2928
],
"typeVersion": 1
},
{
"parameters": {
"content": "**4. Storage & Notify**\nWrites extracted data to Google Sheets and sends Telegram confirmation",
"height": 80,
"width": 300
},
"id": "8ee34964-3992-4791-a194-796608c900ca",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
2800
],
"typeVersion": 1
},
{
"parameters": {
"modelName": "models/gemini-2.5-flash-preview-05-20",
"options": {}
},
"id": "433f85a1-a7e8-47de-8b41-062815be3bf1",
"name": "Gemini Vision Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
384,
2576
],
"typeVersion": 1
},
{
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"type": "n8n-nodes-base.telegramTrigger",
"typeVersion": 1.2,
"position": [
-320,
2416
],
"id": "c11933ac-16cb-42ea-b1ee-46b5c8d5c6eb",
"name": "Receive Invoice Photo",
"notes": "Chat-ID : YOUR_CHAT_ID_2"
},
{
"parameters": {
"resource": "file",
"fileId": "={{ $json.message.photo[3].file_id }}",
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
-96,
2416
],
"id": "20289c44-679e-49fe-b5da-52b1255b77fb",
"name": "Download Photo File"
},
{
"parameters": {
"chatId": "YOUR_CHAT_ID_1",
"text": "={{ $json.Message }}",
"additionalFields": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
496,
2640
],
"id": "fe5b1162-21b9-49a0-8448-35686ccb700a",
"name": "Send Confirmation",
"alwaysOutputData": false,
"executeOnce": false,
"retryOnFail": false
},
{
"parameters": {
"promptType": "define",
"text": "Generate a caption for this image.",
"hasOutputParser": true,
"messages": {
"messageValues": [
{
"message": "=You are a Precision OCR Engine. Your task is to extract all visible and legible text from images with high accuracy and fidelity. Output only the exact text appearing in the image, maintaining its original case. Preserve the natural reading order (e.g., top-to-bottom, left-to-right). Do not infer, summarize, correct, or add any information not explicitly visible.\n\nIf text is partially visible/illegible, extract only what can be confidently read. \n\nMaintain original line breaks and significant structural spacing where present. If no readable text exists, respond solely with an empty string: \"\". \n\nYour primary objective is an accurate, faithful textual representation of the image."
},
{
"type": "HumanMessagePromptTemplate",
"messageType": "imageBinary"
}
]
}
},
"id": "3f5fc96c-0a78-47ba-9b7e-db768efbf415",
"name": "OCR Extract Text",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
352,
2416
],
"typeVersion": 1.4
},
{
"parameters": {
"promptType": "define",
"text": "=<parsed-invoice>\n{{ $json.text }}\n</parsed-invoice>",
"messages": {
"messageValues": [
{
"message": "You are an AI data extractor. Your task is to convert the provided invoice (<parsed-invoice>) text into a single, valid JSON object.\n\n**Key Instructions:**\n\n1. **Output JSON Only:** Your entire response MUST be the JSON object. No explanations or any other text.\n2. **Key Creation:**\n * Keys must be **`snake_case`** and in **English**.\n\n * **Prioritize these standard keys** (grouped for clarity):\n\n * **Supplier & Recipient:**\n * `supplier_name`, `supplier_address`, `supplier_contact_details`, `supplier_tax_id`, `supplier_vat_number`\n * `recipient_business_name`, `recipient_business_address`\n * **Invoice Core Details:**\n * `invoice_number`, `invoice_date`, `purchase_order_number`, `internal_reference_number`\n * **Payment & Financials:**\n * `due_date`, `payment_terms`, `supplier_bank_account_details`\n * `total_amount_due`, `currency_code`\n * `subtotal_amount`, `tax_amount`, `discount_amount`\n * **Internal Processing:**\n * `date_received`, `department_id`, `cost_center_code`, `approver_id`, `approver_name`\n * `date_paid`, `payment_method`, `payment_reference`, `invoice_status`\n * **General:**\n * `notes`\n\n * If invoice text provides a label (e.g., \"Invoice \\#:\") not matching a standard key, use it for the key (e.g., `invoice_hash`).\n\n * For unlabeled info not matching a standard key, **create a concise, descriptive, logical `snake_case` key.**\n\n * If unsure which key to assign, prefix your best guess key with `uncertain_` (e.g., `uncertain_delivery_code`).\n3. **Value Extraction:**\n * Line items: array of objects under `line_items`. Item keys: `snake_case` (e.g., `item_description`, `quantity`, `unit_price`, `line_item_total`; also `product_code`, `item_tax_amount` if applicable).\n4. **Missing Information:** Do not include keys for information not present. Do not invent data.\n\n<parsed-invoice\\>\n\n</parsed-invoice\\>\n\n"
}
]
}
},
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.6,
"position": [
-320,
2640
],
"id": "d976ad29-60c7-4eb7-81a2-c1c2fc4ff060",
"name": "Parse Invoice to JSON"
},
{
"parameters": {
"modelName": "models/gemini-2.5-flash-preview-05-20",
"options": {}
},
"id": "31a763a3-f491-4a7a-a69a-ba21268fb0c0",
"name": "Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-272,
2816
],
"typeVersion": 1
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "252dc06a-a11a-4bd5-b32d-18d700b2ab1c",
"name": "text",
"value": "={{ $json.text.replace(/^(```json\\n)?(.*?)(\\n```)?$/s, '$2')}}",
"type": "object"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
48,
2640
],
"id": "782d098f-5643-4271-b517-e99d6a55683b",
"name": "Clean JSON Response"
},
{
"parameters": {
"authentication": "serviceAccount",
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_BILLING_LEDGER_SHEET_ID",
"mode": "list",
"cachedResultName": "Billing_Ledger",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_BILLING_LEDGER_SHEET_ID/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_BILLING_LEDGER_SHEET_ID/edit#gid=0"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"supplier_name": "={{ $json.text.supplier_name }}",
"supplier_address": "={{ $json.text.supplier_address }}",
"invoice_date": "{{ $json.text.invoice_date }}",
"total_amount_due": "={{ $json.text.total_amount_due }}",
"currency_code": "={{ $json.text.currency_code }}",
"subtotal_amount": "={{ $json.text.total_amount_due }}",
"recipient_business_name": "={{ $json.text.supplier_name }}",
"payment_method": "={{ $json.text.payment_method }}",
"date_paid": "={{ $json.text.transaction_date }}",
"payment_reference": "={{ $json.text.payment_reference }}"
},
"matchingColumns": [],
"schema": [
{
"id": "invoice_number",
"displayName": "invoice_number",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "supplier_name",
"displayName": "supplier_name",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "invoice_date",
"displayName": "invoice_date",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "total_amount_due",
"displayName": "total_amount_due",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "currency_code",
"displayName": "currency_code",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "due_date",
"displayName": "due_date",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "invoice_status",
"displayName": "invoice_status",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "purchase_order_number",
"displayName": "purchase_order_number",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "subtotal_amount",
"displayName": "subtotal_amount",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "tax_amount",
"displayName": "tax_amount",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "payment_terms",
"displayName": "payment_terms",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "date_received",
"displayName": "date_received",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "supplier_tax_id",
"displayName": "supplier_tax_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "supplier_vat_number",
"displayName": "supplier_vat_number",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "recipient_business_name",
"displayName": "recipient_business_name",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "date_paid",
"displayName": "date_paid",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "payment_method",
"displayName": "payment_method",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "payment_reference",
"displayName": "payment_reference",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "discount_amount",
"displayName": "discount_amount",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "approver_id",
"displayName": "approver_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "approver_name",
"displayName": "approver_name",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "department_id",
"displayName": "department_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "cost_center_code",
"displayName": "cost_center_code",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "supplier_address",
"displayName": "supplier_address",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "supplier_contact_details",
"displayName": "supplier_contact_details",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "supplier_bank_account_details",
"displayName": "supplier_bank_account_details",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "internal_reference_number",
"displayName": "internal_reference_number",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "recipient_business_address",
"displayName": "recipient_business_address",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "notes",
"displayName": "notes",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.6,
"position": [
288,
2768
],
"id": "6ccd2351-11d2-4a74-97e6-f28514662874",
"name": "Write to Billing Ledger"
},
{
"parameters": {
"borderWidth": 1,
"borderHeight": 1,
"options": {}
},
"id": "fca064bc-819c-48d2-a704-533da62e739c",
"name": "Process Image",
"type": "n8n-nodes-base.editImage",
"position": [
128,
2416
],
"typeVersion": 1
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "1e51a7f2-4bda-4d41-895f-1bacac630ed9",
"name": "Message",
"value": "=---\n{{ $now }}\n---\n{{ $json.text.toJsonString().substr(0, 1000).replace(/,/g, ',\\n') }}\n",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
288,
2656
],
"id": "6ae485c5-042f-4dd0-95e1-f2dbcd85a648",
"name": "Format Notification"
},
{
"parameters": {
"content": "## Extract Invoice Data from Telegram Image and Log to Google Sheet\n\n### How it works\n1. A Telegram user sends an image (e.g., a scanned invoice) to the bot.\n2. The workflow downloads the photo, runs a Gemini OCR model to extract raw text.\n3. An LLM chain formats the extracted text into a structured JSON invoice object.\n4. Key fields (supplier, date, amount, currency, etc.) are written to a Google Sheet ledger.\n5. A concise summary with a timestamp is sent back to the user via Telegram.\n\n### Setup\n- [ ] Connect your Telegram bot credentials.\n- [ ] Add a Google Service Account with Sheets write access.\n- [ ] Provide the target Google Sheet ID and sheet name.\n- [ ] Enable the Google Gemini API and add the API key.\n- [ ] Ensure the bot has permission to receive photos.\n- [ ] Test with a sample invoice image to verify JSON mapping.",
"height": 768,
"width": 400,
"color": 7
},
"id": "486b429f-c2eb-415a-8e42-7ec82250ea0c",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-800,
2240
],
"typeVersion": 1
}
],
"connections": {
"Gemini Vision Model": {
"ai_languageModel": [
[
{
"node": "OCR Extract Text",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Receive Invoice Photo": {
"main": [
[
{
"node": "Download Photo File",
"type": "main",
"index": 0
}
]
]
},
"Download Photo File": {
"main": [
[
{
"node": "Process Image",
"type": "main",
"index": 0
}
]
]
},
"OCR Extract Text": {
"main": [
[
{
"node": "Parse Invoice to JSON",
"type": "main",
"index": 0
}
]
]
},
"Parse Invoice to JSON": {
"main": [
[
{
"node": "Clean JSON Response",
"type": "main",
"index": 0
}
]
]
},
"Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "Parse Invoice to JSON",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Clean JSON Response": {
"main": [
[
{
"node": "Write to Billing Ledger",
"type": "main",
"index": 0
},
{
"node": "Format Notification",
"type": "main",
"index": 0
}
]
]
},
"Process Image": {
"main": [
[
{
"node": "OCR Extract Text",
"type": "main",
"index": 0
}
]
]
},
"Format Notification": {
"main": [
[
{
"node": "Send Confirmation",
"type": "main",
"index": 0
}
]
]
}
},
"meta": {
"templateCredsSetupCompleted": true
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Telegram-Invoice-Ocr-To-Excel.N8N. Uses lmChatGoogleGemini, telegramTrigger, telegram, chainLlm. Event-driven trigger; 16 nodes.
Source: https://github.com/runfish5/micro-services/blob/main/projects/n8n/00_telegram-invoice-ocr-to-excel/telegram-invoice-ocr-to-excel.n8n.json — 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.
This workflow creates a multi-talented AI assistant named Simran that interacts with users via Telegram. It can handle text and voice messages, understand the user's intent, and perform various tasks.
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
This workflow turns any URL sent to a Telegram bot into ready-to-publish social posts: Trigger: Telegram message (checks if it contains a URL). Fetch & parse: Downloads the page and extracts readable
Auto-Generate Social Media Posts From Urls With Ai Telegram Multi-Platform Posting. Uses telegramTrigger, httpRequest, googleSheets, openAi. Event-driven trigger; 42 nodes.
Generate AI images using Pollinations API, or Generate blog articles using Gemini AI