AutomationFlowsGeneral › LINE Bot Record Receipts to Google Sheets

LINE Bot Record Receipts to Google Sheets

Original n8n title: Line Bot - Google Sheets Record Receipt

LINE BOT - Google Sheets Record Receipt. Uses stickyNote, httpRequest, googleDrive, googleSheets. Webhook trigger; 12 nodes.

Webhook trigger★★★★☆ complexity12 nodesHTTP RequestGoogle DriveGoogle Sheets
General Trigger: Webhook Nodes: 12 Complexity: ★★★★☆ Added:

This workflow follows the Google Drive → 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": "QOePbDNCilLhfzbs",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "LINE BOT - Google Sheets Record Receipt",
  "tags": [],
  "nodes": [
    {
      "id": "c9a6882e-8971-4f8b-8dc4-730e217200f9",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1260,
        100
      ],
      "parameters": {
        "width": 400,
        "height": 500,
        "content": "## Prepare data\n**- Get content image from Line** \nhttps://api-data.line.me/v2/bot/message/xxx/content\n\n**- Get image URL to Binary**"
      },
      "typeVersion": 1
    },
    {
      "id": "b766ad37-ec63-4006-80a7-048307afd23a",
      "name": "Image slip URL in Line",
      "type": "n8n-nodes-base.set",
      "position": [
        -1200,
        300
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f8b8ac7c-5c5f-452f-a84d-e068bb248eb5",
              "name": "file_url",
              "type": "string",
              "value": "=https://api-data.line.me/v2/bot/message/{{ $json.body.events[0].message.id }}/content"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "172ed09e-8caf-4bee-9f09-a9b8b00470f7",
      "name": "Get image to Binary",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1000,
        300
      ],
      "parameters": {
        "url": "={{ $json.file_url }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "79753b3d-d6a9-4047-af48-947e6221de48",
      "name": "Line Chat Bot",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1440,
        300
      ],
      "parameters": {
        "path": "23ba996d-3242-42a1-946c-f04a680b320a",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "91837828-c24d-4999-a6db-9323394b8e77",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -840,
        100
      ],
      "parameters": {
        "color": 2,
        "width": 220,
        "height": 500,
        "content": "## Upload image to Google Drive\n"
      },
      "typeVersion": 1
    },
    {
      "id": "94be83d7-5070-4f94-ae33-0a9695fc0b25",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -600,
        100
      ],
      "parameters": {
        "color": 3,
        "width": 540,
        "height": 500,
        "content": "## OCR and get value\n**- OCR API by SpaceOCR**\nhttps://api.ocr.space/parse/imageurl?apikey=YOURAPI&language=tha&isOverlayRequired=false&OCREngine=2&filetype=JPG&url=xxx\n\n**- Parse Transaction Details**"
      },
      "typeVersion": 1
    },
    {
      "id": "5e269f18-c666-4ba3-bb92-e60f5761cf0e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        100
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 500,
        "content": "## Store Data in Google Sheets"
      },
      "typeVersion": 1
    },
    {
      "id": "aa5312d8-304c-4d64-839b-a4464cb0d60e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1500,
        100
      ],
      "parameters": {
        "color": 5,
        "width": 220,
        "height": 500,
        "content": "## LINE Webhook Trigger \n**(Receive Image)**"
      },
      "typeVersion": 1
    },
    {
      "id": "802a7b11-38bf-4dd1-ae32-cd6b6071b9dd",
      "name": "Upload image to Google Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -780,
        300
      ],
      "parameters": {
        "name": "={{ $('Line Chat Bot').item.json.body.events[0].message.id }}.jpg",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "url",
          "value": "https://drive.google.com/drive/folders/1M-j_Gt6yKM1K8SISWknaGQyPQn52AaK1"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "b37b4b7a-1030-44d0-8f57-90acca085e5a",
      "name": "Record in Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        20,
        300
      ],
      "parameters": {
        "columns": {
          "value": {
            "Fee": "={{ $json.fee }}",
            "Amount": "={{ $json.amount }}",
            "Date & Time": "={{ $json.date_time }}",
            "Sender Name": "={{ $json.sender_name }}",
            "Receiver Bank": "={{ $json.receiver_bank }}",
            "Receiver Name": "={{ $json.receiver_name }}",
            "Sender Account": "={{ $json.sender_account }}",
            "Transaction ID": "={{ $json.transaction_id }}",
            "Receiver Account": "={{ $json.receiver_account }}",
            "Transaction Type": "={{ $json.transaction_type }}"
          },
          "schema": [
            {
              "id": "Transaction Type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Transaction Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date & Time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Date & Time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Bank",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Bank",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sender Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Sender Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sender Account",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Sender Account",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Receiver Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Receiver Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Receiver Bank",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Receiver Bank",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Receiver Account",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Receiver Account",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Transaction ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Transaction ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Fee",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Fee",
              "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/1IpvzcnWmb-aLpSleTIF0xoF8xzbOOJQhuT6ITAeEQks/edit#gid=0",
          "cachedResultName": "data"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/1IpvzcnWmb-aLpSleTIF0xoF8xzbOOJQhuT6ITAeEQks/edit?gid=0#gid=0"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "22fbba4f-ad1f-43a5-99de-db7084cd3fc5",
      "name": "Send Image URL to OCR Space for Text Extraction",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -520,
        300
      ],
      "parameters": {
        "url": "=https://api.ocr.space/parse/imageurl?apikey=K82173083188957&language=tha&isOverlayRequired=false&OCREngine=2&filetype=JPG&url={{ \"https://drive.google.com/uc?id=\" + $json[\"id\"] }}\n",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "678993d0-8301-42d5-93cd-7839d42b71bc",
      "name": "Extract Transaction Details",
      "type": "n8n-nodes-base.code",
      "position": [
        -260,
        300
      ],
      "parameters": {
        "jsCode": "const text = $json[\"ParsedResults\"][0][\"ParsedText\"];\n\n// Split text by line breaks and trim spaces\nconst lines = text.split(\"\\n\").map(line => line.trim());\n\n// Debugging: Log extracted lines for verification\nconsole.log(\"Extracted Lines:\", lines);\n\n// Helper function to find text after a keyword, with OCR variations\nfunction getValueAfterKeyword(keywords, offset = 1) {\n    let index = lines.findIndex(line => keywords.some(keyword => line.includes(keyword)));\n    return index !== -1 && lines[index + offset] ? lines[index + offset] : null;\n}\n\n// **Extracting Data for Both Standard & PromptPay Transactions**\nconst transaction_type = lines[0] || null;  // First line\nconst date_time = lines[1] || null;  // Second line\n\n// **Sender Details**\nconst sender_name_index = lines.findIndex(line => line.startsWith(\"\u0e19\u0e32\u0e22\"));\nconst sender_name = sender_name_index !== -1 ? lines[sender_name_index] : null;\nconst sender_bank = sender_name_index !== -1 ? lines[sender_name_index + 1] : null;\nconst sender_account = sender_name_index !== -1 ? lines[sender_name_index + 2] : null;\n\n// **Determine if it's a Standard Bank Transfer or PromptPay**\nconst isPromptPay = lines.some(line => line.includes(\"Prompt\") || line.includes(\"\u0e23\u0e2b\u0e31\u0e2a\u0e1e\u0e23\u0e49\u0e2d\u0e21\u0e40\u0e1e\u0e22\u0e4c\"));\nlet receiver_name = null;\nlet receiver_bank = null;\nlet receiver_account = null;\n\nif (isPromptPay) {\n    // **Handling PromptPay Transactions**\n    const receiver_index = lines.findIndex(line => line.includes(\"Prompt\"));\n    receiver_bank = \"PromptPay\"; // Fixed for PromptPay transactions\n    receiver_name = receiver_index !== -1 ? lines[receiver_index + 2] : null; // Receiver's actual name\n\n    // **Fix Receiver Account for PromptPay**\n    const receiver_account_index = lines.findIndex(line => line.includes(\"\u0e23\u0e2b\u0e31\u0e2a\u0e1e\u0e23\u0e49\u0e2d\u0e21\u0e40\u0e1e\u0e22\u0e4c\"));\n    receiver_account = receiver_account_index !== -1 ? lines[receiver_account_index + 1] : null; // The actual account number\n\n} else {\n    // **Handling Standard Bank Transfers**\n    const receiver_index = lines.findIndex(line => line.includes(\"\u0e19\u0e34\u0e15\u0e34\u0e1a\u0e38\u0e04\u0e04\u0e25\") || line.includes(\"\u0e1a\u0e23\u0e34\u0e29\u0e31\u0e17\") || line.includes(\"\u0e19\u0e32\u0e22\"));\n    receiver_name = receiver_index !== -1 ? lines[receiver_index] : null;\n    receiver_bank = receiver_index !== -1 ? lines[receiver_index + 2] : null;\n    receiver_account = receiver_index !== -1 ? lines[receiver_index + 3] : null;\n}\n\n// **Fix Transaction ID Extraction**\nlet transaction_id = null;\n\n// **First, try \"\u0e40\u0e25\u0e02\u0e17\u0e35\u0e48\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23:\" for Standard Transactions**\nconst transaction_index = lines.findIndex(line => line.includes(\"\u0e40\u0e25\u0e02\u0e17\u0e35\u0e48\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23:\"));\nif (transaction_index !== -1) {\n    if (/\\d{10,}/.test(lines[transaction_index])) {\n        // If the same line contains the transaction ID, extract it\n        transaction_id = lines[transaction_index].match(/\\d{10,}/)[0];\n    } else if (transaction_index + 1 < lines.length && /\\d{10,}/.test(lines[transaction_index + 1])) {\n        // If transaction ID is on the next line, extract it\n        transaction_id = lines[transaction_index + 1];\n    }\n}\n\n// \u2705 **If transaction_id is still missing, use \"\u0e08\u0e33\u0e19\u0e27\u0e19:\" or possible OCR errors (\"\u0e08\u0e33\u0e19\u0e27\u0e19\u0e30\")**\nif (!transaction_id) {\n    let amount_index = lines.findIndex(line => line.includes(\"\u0e08\u0e33\u0e19\u0e27\u0e19\") || line.includes(\"\u0e08\u0e33\u0e19\u0e27\u0e19\u0e30\"));\n    if (amount_index !== -1) {\n        for (let i = amount_index + 1; i < lines.length; i++) {\n            if (/^[A-Za-z0-9]+$/.test(lines[i])) { // Ensure it's a valid ID\n                transaction_id = lines[i];\n                break; // **Break early for efficiency**\n            }\n        }\n    }\n}\n\n// **Extract Amount Correctly**\nconst amount_index = lines.findIndex(line => line.includes(\"\u0e1a\u0e32\u0e17\") && !line.includes(\"\u0e04\u0e48\u0e32\u0e18\u0e23\u0e23\u0e21\u0e40\u0e19\u0e35\u0e22\u0e21\"));\nconst amount = amount_index !== -1 ? lines[amount_index].replace(\" \u0e1a\u0e32\u0e17\", \"\").replace(/[^0-9.]/g, \"\") : null;\n\n// **Extract Fee Correctly**\nconst fee_index = lines.findIndex(line => line.includes(\"\u0e04\u0e48\u0e32\u0e18\u0e23\u0e23\u0e21\u0e40\u0e19\u0e35\u0e22\u0e21\"));\nconst fee = fee_index !== -1 && lines[fee_index + 1] ? lines[fee_index + 1].replace(\" \u0e1a\u0e32\u0e17\", \"\").replace(/[^0-9.]/g, \"\") : null;\n\n// **Ensure Essential Details Exist**\nif (transaction_type && date_time && sender_name && sender_bank && sender_account && receiver_name && receiver_bank && receiver_account && transaction_id && amount) {\n    return [\n        {\n            json: {\n                \"transaction_type\": transaction_type,\n                \"date_time\": date_time,\n                \"sender_name\": sender_name,\n                \"sender_bank\": sender_bank,\n                \"sender_account\": sender_account,\n                \"receiver_name\": receiver_name,\n                \"receiver_bank\": receiver_bank,\n                \"receiver_account\": receiver_account,\n                \"transaction_id\": transaction_id,\n                \"amount\": amount,\n                \"fee\": fee\n            }\n        }\n    ];\n} else {\n    return [\n        {\n            json: {\n                \"error\": \"Some values could not be extracted\",\n                \"raw_text\": text\n            }\n        }\n    ];\n}\n"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e1708774-49cf-4cbb-a4c4-9fefccd0fedb",
  "connections": {
    "Line Chat Bot": {
      "main": [
        [
          {
            "node": "Image slip URL in Line",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get image to Binary": {
      "main": [
        [
          {
            "node": "Upload image to Google Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Image slip URL in Line": {
      "main": [
        [
          {
            "node": "Get image to Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Transaction Details": {
      "main": [
        [
          {
            "node": "Record in Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload image to Google Drive": {
      "main": [
        [
          {
            "node": "Send Image URL to OCR Space for Text Extraction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Image URL to OCR Space for Text Extraction": {
      "main": [
        [
          {
            "node": "Extract Transaction Details",
            "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

How this works

This workflow enables small business owners and shopkeepers to effortlessly capture and store customer receipts sent via LINE messaging, ensuring accurate financial records without manual data entry. It receives images of receipts through a LINE Bot integration, extracts the image data, and logs essential details directly into Google Sheets for easy tracking and analysis. The key step involves fetching the receipt image via HTTP request and appending it alongside timestamps and sender information to your spreadsheet, streamlining expense management.

Use this workflow when handling frequent LINE-based customer interactions, such as in retail or service industries, to automate receipt archiving and avoid paper clutter. Avoid it for high-volume operations needing advanced OCR for text extraction, as it focuses on basic image storage rather than parsing content. Common variations include adding Google Drive uploads for secure backups or integrating email notifications for urgent receipts.

About this workflow

LINE BOT - Google Sheets Record Receipt. Uses stickyNote, httpRequest, googleDrive, googleSheets. Webhook trigger; 12 nodes.

Source: https://github.com/Zie619/n8n-workflows — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

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

General

Line Save File to Google Drive and Log File's URL. Uses googleSheets, googleDrive, httpRequest, stickyNote. Webhook trigger; 27 nodes.

Google Sheets, Google Drive, HTTP Request
General

Unique QRcode coupon assignment and validation for Lead Generation system. Uses httpRequest, formTrigger, googleSheets, stickyNote. Webhook trigger; 29 nodes.

HTTP Request, Form Trigger, Google Sheets +1
General

AutoQoutesV2_template. Uses manualTrigger, httpRequest, stickyNote, googleSheets. Event-driven trigger; 28 nodes.

HTTP Request, Google Sheets, Google Drive +2
General

AutoClip – Automatically Generate Video Clips and Upload to YouTube. Uses manualTrigger, googleSheets, googleDrive, stickyNote. Event-driven trigger; 23 nodes.

Google Sheets, Google Drive, Read Write File +2
General

Image-to-3D. Uses manualTrigger, httpRequest, scheduleTrigger, stickyNote. Event-driven trigger; 17 nodes.

HTTP Request, Google Sheets, Google Drive