AutomationFlowsAI & RAG › Three-Way Invoice Matching with Google Drive

Three-Way Invoice Matching with Google Drive

Original n8n title: Three-way Invoice Matcher

Three-Way Invoice Matcher. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 8 nodes.

Event trigger★★★★☆ complexity8 nodesGoogle Drive TriggerGoogle DriveN8N Nodes PdfvectorGoogle SheetsSlack
AI & RAG Trigger: Event Nodes: 8 Complexity: ★★★★☆ Added:

This workflow follows the Google Drive → Google Drive Trigger 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": "Three-Way Invoice Matcher",
  "nodes": [
    {
      "parameters": {
        "content": "## \ud83d\udd04 W39 Three-Way Invoice Matcher\n\n### What this workflow does\n1. Watches Google Drive folder for invoice PDFs\n2. Extracts line items, quantities, prices, totals\n3. Looks up matching PO in your Sheets database\n4. Compares quantities and prices\n5. Flags mismatches and discrepancies\n6. Sends Slack alert with match results\n\n### Setup steps\n1. Get PDF Vector API key from pdfvector.com/api-keys\n2. Create a Google Drive folder for invoices\n3. Create a Google Sheet with two tabs:\n   - Tab 1 (PO_Database): PO Number | Vendor | Line Items | Quantities | Prices | Total\n   - Tab 2 (Match_Results): Invoice Number | Vendor | PO Number | Invoice Total | PO Total | Status | Discrepancies | Processed Date\n4. Update the folder ID and sheet ID in the nodes\n5. Connect your Slack workspace\n\n### Perfect for\n- Accounts payable teams\n- Controllers\n- Finance managers\n\n### Template by PDF Vector\npdfvector.com/integrations/n8n",
        "height": 684,
        "width": 596,
        "color": 5
      },
      "id": "5c6861f0-839e-4922-8e16-9035c3d04510",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        10080,
        2976
      ]
    },
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "value": "YOUR_INVOICES_FOLDER_ID",
          "mode": "list"
        },
        "event": "fileCreated",
        "options": {}
      },
      "id": "9b68a218-7215-4e2c-b9f3-ea7a01e81469",
      "name": "New Invoice",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "typeVersion": 1,
      "position": [
        10720,
        3216
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.id }}",
          "mode": "id"
        },
        "options": {}
      },
      "id": "e485f9e2-1fec-40c8-bed0-de58e19ad4bc",
      "name": "Download Invoice",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        10944,
        3216
      ],
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "extract",
        "inputType": "file",
        "prompt": "Extract invoice information for three-way matching including: invoice number, invoice date, vendor name, vendor address, vendor ID or tax ID, purchase order number referenced, bill to name and address, ship to name and address, payment terms, due date, line items with item number/SKU, description, quantity ordered, quantity shipped, quantity invoiced, unit of measure, unit price, extended price, subtotal, freight/shipping charges, tax amount, total amount, and any notes or discrepancies mentioned.",
        "schema": "{\"type\":\"object\",\"properties\":{\"invoiceNumber\":{\"type\":\"string\"},\"invoiceDate\":{\"type\":\"string\"},\"vendorName\":{\"type\":\"string\"},\"vendorAddress\":{\"type\":\"string\"},\"vendorId\":{\"type\":\"string\"},\"poNumber\":{\"type\":\"string\"},\"billToName\":{\"type\":\"string\"},\"billToAddress\":{\"type\":\"string\"},\"shipToName\":{\"type\":\"string\"},\"shipToAddress\":{\"type\":\"string\"},\"paymentTerms\":{\"type\":\"string\"},\"dueDate\":{\"type\":\"string\"},\"lineItemCount\":{\"type\":\"number\"},\"lineItemsSummary\":{\"type\":\"string\"},\"subtotal\":{\"type\":\"number\"},\"freight\":{\"type\":\"number\"},\"tax\":{\"type\":\"number\"},\"totalAmount\":{\"type\":\"number\"},\"notes\":{\"type\":\"string\"}},\"required\":[\"invoiceNumber\",\"vendorName\",\"totalAmount\"],\"additionalProperties\":false}"
      },
      "id": "91959f45-f32a-426d-9292-a6a83537d075",
      "name": "Extract Invoice Data",
      "type": "n8n-nodes-pdfvector.pdfVector",
      "typeVersion": 2,
      "position": [
        11168,
        3216
      ],
      "credentials": {
        "pdfVectorApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "list"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Page 1"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "PO Number",
              "lookupValue": "={{ $json.data.poNumber }}"
            }
          ]
        },
        "options": {}
      },
      "id": "07f10ff4-3ef5-4601-b687-746d488a1bdd",
      "name": "Lookup PO Database",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        11376,
        3216
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const extractNode = $('Extract Invoice Data').first();\nconst invoiceData = extractNode.json.data || extractNode.json;\nconst poRecords = $('Lookup PO Database').all();\nconst triggerData = $('New Invoice').item.json;\nconst fileName = triggerData.name || 'unknown';\nconst fileId   = triggerData.id   || '';\n\nconst invoiceNumber = invoiceData.invoiceNumber || 'Unknown';\nconst poNumber      = invoiceData.poNumber      || '';\nconst vendorName    = invoiceData.vendorName    || 'Unknown';\nconst cleanNum = v => parseFloat(String(v||0).replace(/[^0-9.]/g,'')) || 0;\nconst invoiceTotal  = cleanNum(invoiceData.totalAmount);\n\nlet poMatch = null, matchStatus = 'NO_PO_FOUND', poTotal = 0;\nfor (const po of poRecords) {\n  const poData = po.json;\n  if (poData['PO Number'] === poNumber || poData.poNumber === poNumber) {\n    poMatch = poData;\n    poTotal = cleanNum(poData['Total'] || poData.total);\n    matchStatus = 'PO_FOUND';\n    break;\n  }\n}\n\nlet discrepancies = []; let discrepancyAmount = 0;\nif (poMatch) {\n  const tolerance = poTotal * 0.02;\n  const totalDiff = Math.abs(invoiceTotal - poTotal);\n  if (totalDiff > tolerance) {\n    discrepancyAmount = invoiceTotal - poTotal;\n    discrepancies.push(`Total: Invoice $${invoiceTotal.toFixed(2)} vs PO $${poTotal.toFixed(2)} (Diff: $${discrepancyAmount.toFixed(2)})`);\n    matchStatus = 'PARTIAL_MATCH';\n  } else {\n    matchStatus = 'FULL_MATCH';\n  }\n} else {\n  discrepancies.push('No matching PO found in database');\n}\n\nlet priority = 'Low';\nif (matchStatus === 'NO_PO_FOUND') priority = 'High';\nelse if (matchStatus === 'PARTIAL_MATCH' && Math.abs(discrepancyAmount) > 1000) priority = 'High';\nelse if (matchStatus === 'PARTIAL_MATCH') priority = 'Medium';\n\nreturn [{ json: {\n  invoiceNumber, invoiceDate: invoiceData.invoiceDate || 'N/A',\n  vendorName, poNumber: poNumber || 'Not Referenced',\n  invoiceTotal, poTotal, matchStatus,\n  discrepancies: discrepancies.join('; ') || 'None',\n  priority, fileName, fileId,\n  processedAt: new Date().toISOString(),\n  fileId: fileId,\n  matchStatus: matchStatus,\n  poNumber: poNumber || 'Not Referenced',\n  poTotal: poTotal,\n}}];"
      },
      "id": "729ac25d-d2cc-48d0-ba87-7267b9e6377d",
      "name": "Three-Way Match",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        11600,
        3216
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "list"
        },
        "sheetName": {
          "__rl": true,
          "value": 2060479334,
          "mode": "list",
          "cachedResultName": "Page 2"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Invoice Number": "={{ $json.invoiceNumber }}",
            "Vendor": "={{ $json.vendorName }}",
            "PO Number": "={{ $json.poNumber }}",
            "Invoice Total": "={{ $json.invoiceTotal }}",
            "PO Total": "={{ $json.poTotal }}",
            "Status": "={{ $json.matchStatus }}",
            "Discrepancies": "={{ $json.discrepancies }}",
            "Processed Date": "={{ $json.processedAt.split('T')[0] }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "Invoice Number",
              "displayName": "Invoice Number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "displayName": "Vendor",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "PO Number",
              "displayName": "PO Number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Total",
              "displayName": "Invoice Total",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "PO Total",
              "displayName": "PO Total",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "displayName": "Status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Discrepancies",
              "displayName": "Discrepancies",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed Date",
              "displayName": "Processed Date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "id": "41f79ebc-9cee-494b-a26a-8d047750cb21",
      "name": "Log Match Results",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        11824,
        3216
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "YOUR_SLACK_CHANNEL_ID",
          "mode": "list"
        },
        "text": "=\ud83d\udd04 *Three-Way Match Result*\n\n*Invoice:* {{ $('Three-Way Match').item.json.invoiceNumber }}\n*Vendor:* {{ $('Three-Way Match').item.json.vendorName }}\n*PO:* {{ $('Three-Way Match').item.json.poNumber }}\n\n\ud83d\udcca *Status:* {{ $('Three-Way Match').item.json.matchStatus }}\n*Priority:* {{ $('Three-Way Match').item.json.priority }}\n\n\ud83d\udcb0 *Amounts:*\n\u2022 Invoice: ${{ $('Three-Way Match').item.json.invoiceTotal }}\n\u2022 PO: ${{ $('Three-Way Match').item.json.poTotal }}\n\n\u26a0\ufe0f *Discrepancies:*\n{{ $('Three-Way Match').item.json.discrepancies }}\n\n\ud83d\udd17 <https://drive.google.com/file/d/{{ $('Three-Way Match').item.json.fileId }}/view|View Invoice>",
        "otherOptions": {}
      },
      "id": "5ec33cee-71dc-4a37-825e-5b140c730663",
      "name": "Send to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        12048,
        3216
      ],
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "New Invoice": {
      "main": [
        [
          {
            "node": "Download Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Invoice": {
      "main": [
        [
          {
            "node": "Extract Invoice Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Invoice Data": {
      "main": [
        [
          {
            "node": "Lookup PO Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup PO Database": {
      "main": [
        [
          {
            "node": "Three-Way Match",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Three-Way Match": {
      "main": [
        [
          {
            "node": "Log Match Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Match Results": {
      "main": [
        [
          {
            "node": "Send to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "availableInMCP": false
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

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

Three-Way Invoice Matcher. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 8 nodes.

Source: https://github.com/khanhduyvt0101/workflows/blob/0153ee2efc0f692c931b9bb4c2a04abf11756822/n8n-workflows/three-way-invoice-matcher.json — 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

Lease Agreement Analyzer for Renters. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 12 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Expense Report Processor with AI Categorization. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 12 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Financial Report Analyzer (10-K, 10-Q). Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 11 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

AI Contract Review & Risk Analysis. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 10 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2
AI & RAG

Patient Intake Form Processor for Healthcare. Uses googleDriveTrigger, googleDrive, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 10 nodes.

Google Drive Trigger, Google Drive, N8N Nodes Pdfvector +2