AutomationFlowsData & Sheets › Classify Documents and Extract Invoice Data with Ldxhub Analyzedoc and…

Classify Documents and Extract Invoice Data with Ldxhub Analyzedoc and…

Original n8n title: Classify Documents and Extract Invoice Data with Ldxhub Analyzedoc and Google Sheets

ByHideki Mori @hidekimori on n8n.io

This workflow collects uploaded PDFs or images, classifies each document type using LDXhub AnalyzeDoc, and routes it accordingly; invoices get high-detail field extraction and are appended as a new row in Google Sheets. Receives a file upload through an n8n form for a PDF, JPG,…

Event trigger★★★★☆ complexity16 nodesForm TriggerN8N Nodes LdxhubGoogle Sheets
Data & Sheets Trigger: Event Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #17039 — we link there as the canonical source.

This workflow follows the Form Trigger → 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
{
  "name": "Classify Mixed Documents and Route Invoices to Google Sheets with LDX hub AnalyzeDoc",
  "nodes": [
    {
      "id": "906856cd-b673-4245-9232-dca6e9e28584",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -660,
        -480
      ],
      "parameters": {
        "width": 500,
        "height": 1120,
        "content": "## How it works\n\nUpload any business document (PDF, JPEG, or PNG). A **low-detail** AnalyzeDoc pass classifies it \u2014 invoice, receipt, business card, contract, blank, or other \u2014 then a Switch routes the file by type.\n\nLow detail costs roughly 1/5\u20131/10 of a high-detail read. It reads titles and layout reliably, but not fine print \u2014 so classify cheap first, and spend high-detail credits only where extraction is actually needed.\n\nThe **invoice route is fully wired**: the original file is re-attached and sent through a high-detail extraction that pulls 12 key fields and appends them as one row to Google Sheets. The other routes are placeholders for your own flows.\n\n### Setup steps\n\n1. Get a free API key at gw.portal.ldxhub.io (25,000 credits/month, no credit card).\n2. Create an LDXhub API credential and select it in **both** AnalyzeDoc nodes.\n3. Connect Google Sheets credentials and pick a spreadsheet whose first row has these headers: invoice_number, issue_date, due_date, vendor_name, vendor_address, vendor_tax_id, bill_to, subtotal, tax, total, currency, payment_terms.\n4. In the Sheets node, after picking the sheet, set Mapping Column Mode back to **Map Automatically** \u2014 n8n switches it to manual whenever a sheet is selected.\n5. Run the workflow and upload a document.\n\n### Customization\n\n- Add or rename document types in both the classification prompt and the Switch rules.\n- If your document types share nearly identical layouts, add \"identify the type from the document title\" to the classification prompt.\n- Replace the No-Op placeholders with your own processing (OCR conversion, filing, notifications)."
      },
      "typeVersion": 1
    },
    {
      "id": "71c2263d-43d6-4044-9a1c-70296663e964",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        -180
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 340,
        "content": "## Classify cheaply\n\nA low-detail vision pass assigns one of six document types. Ideal as a sorting gate for mixed scan folders."
      },
      "typeVersion": 1
    },
    {
      "id": "9e53534d-f0ba-4421-aa8d-f0af3cce2d11",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        -520
      ],
      "parameters": {
        "color": 7,
        "width": 1200,
        "height": 460,
        "content": "## Invoice route (fully wired)\n\nThe first Code node re-attaches the original upload (binary data does not survive the parse step). After the **high-detail** extraction, a second Code node lifts the parsed fields from `data` to the top level so Google Sheets auto-mapping matches your column headers \u2014 just pick your spreadsheet.\n\nTip: keep example amounts as decimals (e.g. 1234.56) so they stay numeric."
      },
      "typeVersion": 1
    },
    {
      "id": "a2a27694-dd92-4575-be31-2ec229e182bf",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        40
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 660,
        "content": "## Your routes\n\nreceipt and business_card land here; everything else falls through to **other**. Replace the No-Ops with your own flows."
      },
      "typeVersion": 1
    },
    {
      "id": "f0a38eba-54f9-483f-9bad-10c56ceb233b",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "options": {
          "buttonLabel": "Classify"
        },
        "formTitle": "Sort Documents by Type",
        "formFields": {
          "values": [
            {
              "fieldName": "document_file",
              "fieldType": "file",
              "fieldLabel": "Document File",
              "multipleFiles": false,
              "requiredField": true,
              "acceptFileTypes": ".pdf,.jpg,.jpeg,.png"
            }
          ]
        },
        "formDescription": "Upload a business document (PDF, JPEG, or PNG). A low-cost AI pass classifies it and routes it by type; invoices are extracted to Google Sheets."
      },
      "typeVersion": 2.5
    },
    {
      "id": "51ae9e09-2a5a-4910-adde-4b90dea4cfbd",
      "name": "AnalyzeDoc: Classify Document",
      "type": "n8n-nodes-ldxhub.ldxHub",
      "position": [
        224,
        0
      ],
      "parameters": {
        "model": "google/gemini-3.5-flash@low",
        "resource": "analyzeDoc",
        "output_format": "json",
        "system_prompt": "Classify this document image into exactly one of these types: invoice, receipt, business_card, contract, blank, other. Judge from the overall layout and structure of the page.",
        "example_output": "{\"document_type\": \"other\", \"reason\": \"layout does not match any listed type\"}",
        "pollingSettings": {
          "serverWaitSeconds": 10,
          "pollingMaxAttempts": 180
        },
        "binaryPropertyName": "document_file"
      },
      "credentials": {
        "ldxHubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "40b6c92c-47ad-42a9-b2a9-dfe63d11df33",
      "name": "Parse Classification",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        448,
        0
      ],
      "parameters": {
        "options": {},
        "operation": "fromJson",
        "binaryPropertyName": "document_file"
      },
      "typeVersion": 1
    },
    {
      "id": "364883a1-cf35-46cf-b55d-7fb703c2b066",
      "name": "Route by Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        672,
        0
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "invoice",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "230d22e3-fdb5-478d-b619-e2242ebb97cb",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.document_type }}",
                    "rightValue": "invoice"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "receipt",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "304d86e8-473e-4715-905a-9876e6330236",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.document_type }}",
                    "rightValue": "receipt"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "business_card",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "8870e9b1-f26a-4576-8521-432642c6a277",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.document_type }}",
                    "rightValue": "business_card"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "other"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "ba8c3bc4-c118-4561-9409-504b57e894c9",
      "name": "Reattach Original File",
      "type": "n8n-nodes-base.code",
      "position": [
        960,
        -256
      ],
      "parameters": {
        "jsCode": "return $input.all().map(item => ({\n  json: item.json,\n  binary: $('On form submission').item.binary\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "bcb4796c-7289-4807-8326-b35d885e2ad8",
      "name": "AnalyzeDoc: Extract Invoice Fields",
      "type": "n8n-nodes-ldxhub.ldxHub",
      "position": [
        1184,
        -256
      ],
      "parameters": {
        "model": "google/gemini-3.5-flash@high",
        "resource": "analyzeDoc",
        "output_format": "json",
        "system_prompt": "Extract the key fields from this invoice. Rules: Dates in YYYY-MM-DD format. All amounts as plain numbers (no currency symbols, no thousands separators). vendor_tax_id is the vendor's tax or registration number if present. payment_terms exactly as written on the invoice (e.g., \"Net 30\"). Use an empty string for any field that is not present.",
        "example_output": "{\"invoice_number\": \"\", \"issue_date\": \"\", \"due_date\": \"\", \"vendor_name\": \"\", \"vendor_address\": \"\", \"vendor_tax_id\": \"\", \"bill_to\": \"\", \"subtotal\": 1234.56, \"tax\": 123.45, \"total\": 1358.01, \"currency\": \"\", \"payment_terms\": \"\"}",
        "pollingSettings": {
          "serverWaitSeconds": 10,
          "pollingMaxAttempts": 180
        },
        "binaryPropertyName": "document_file"
      },
      "credentials": {
        "ldxHubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "025c69ae-46e9-46d4-bf39-3c34b63ef3bf",
      "name": "Parse Invoice JSON",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1408,
        -256
      ],
      "parameters": {
        "options": {},
        "operation": "fromJson",
        "binaryPropertyName": "document_file"
      },
      "typeVersion": 1
    },
    {
      "id": "7c18dd04-dc58-4d28-ab34-8d5fe4ba64fc",
      "name": "Append Invoice to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1856,
        -256
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "197b358c-1608-4b2e-8af7-2c1754607fbd",
      "name": "Receipt: Add Your Flow",
      "type": "n8n-nodes-base.noOp",
      "position": [
        960,
        240
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e2a04d6d-cf8b-48d4-b42a-8424ddcbc204",
      "name": "Business Card: Add Your Flow",
      "type": "n8n-nodes-base.noOp",
      "position": [
        960,
        390
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "0bda3f30-ab30-4bf9-811d-1aa53deaf350",
      "name": "Other: Review Manually",
      "type": "n8n-nodes-base.noOp",
      "position": [
        960,
        540
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "c02147b9-94f7-4bc6-a561-65ca0e2b11b1",
      "name": "Flatten for Sheets",
      "type": "n8n-nodes-base.code",
      "position": [
        1632,
        -256
      ],
      "parameters": {
        "jsCode": "// Lift the parsed fields from $json.data to the top level\n// so Google Sheets auto-mapping can match them to your column headers.\nreturn $input.all().map(item => ({ json: item.json.data }));"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "connections": {
    "Route by Type": {
      "main": [
        [
          {
            "node": "Reattach Original File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Receipt: Add Your Flow",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Business Card: Add Your Flow",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Other: Review Manually",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Flatten for Sheets": {
      "main": [
        [
          {
            "node": "Append Invoice to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "AnalyzeDoc: Classify Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Invoice JSON": {
      "main": [
        [
          {
            "node": "Flatten for Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Classification": {
      "main": [
        [
          {
            "node": "Route by Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reattach Original File": {
      "main": [
        [
          {
            "node": "AnalyzeDoc: Extract Invoice Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AnalyzeDoc: Classify Document": {
      "main": [
        [
          {
            "node": "Parse Classification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AnalyzeDoc: Extract Invoice Fields": {
      "main": [
        [
          {
            "node": "Parse Invoice JSON",
            "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

This workflow collects uploaded PDFs or images, classifies each document type using LDXhub AnalyzeDoc, and routes it accordingly; invoices get high-detail field extraction and are appended as a new row in Google Sheets. Receives a file upload through an n8n form for a PDF, JPG,…

Source: https://n8n.io/workflows/17039/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

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

Data & Sheets

This workflow collects a meeting-minutes PDF via an n8n form, uses LDX hub (Gemini) to segment it by agenda and extract decisions and action items, then appends each item as a row in Google Sheets. Re

Form Trigger, N8N Nodes Ldxhub, Google Sheets
Data & Sheets

This workflow collects a business card photo/scan through an n8n form, uses LDX hub AnalyzeDoc (Gemini) to extract contact details as structured JSON, and appends the resulting fields as a new row in

Form Trigger, N8N Nodes Ldxhub, Google Sheets
Data & Sheets

This workflow collects an invoice PDF or image through an n8n form, uses LDX hub AnalyzeDoc (Gemini) to extract key invoice fields as JSON, and appends the results as a new row in Google Sheets. Recei

Form Trigger, N8N Nodes Ldxhub, Google Sheets
Data & Sheets

Ultimate Extract by RoboNuggets (R46). Uses @apify/n8n-nodes-apify, googleSheets, formTrigger. Event-driven trigger; 42 nodes.

@Apify/N8N Nodes Apify, Google Sheets, Form Trigger
Data & Sheets

Overview 🌐

Form Trigger, HTTP Request, Google Sheets