AutomationFlowsAI & RAG › Reconcile Google Drive Invoice Pdfs with Openai, Sheets, Slack and Gmail

Reconcile Google Drive Invoice Pdfs with Openai, Sheets, Slack and Gmail

ByRedowan Ahmed Farhan @redowanfarhan on n8n.io

How it works

Event trigger★★★★☆ complexityAI-powered16 nodesGoogle SheetsSlackGmailGoogle DriveAgentOpenAI ChatGoogle Drive Trigger
AI & RAG Trigger: Event Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → Gmail 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
{
  "nodes": [
    {
      "id": "40768100-aea3-4fa5-85a3-83d3ca931676",
      "name": "04 | Code Split PDF Attachments into Items",
      "type": "n8n-nodes-base.code",
      "position": [
        1136,
        448
      ],
      "parameters": {
        "jsCode": "const results = [];\n\nfor (const item of $input.all()) {\n  // Grab the extracted PDF text\n  const pdfText = item.json.text || item.json.content || '';\n\n  // Grab Drive file metadata carried from the trigger\n  const driveData = item.json;\n\n  results.push({\n    json: {\n      emailId: driveData.id || driveData.name || 'drive_' + Date.now(),\n      from: driveData.owners?.[0]?.emailAddress || 'drive-upload',\n      subject: driveData.name || 'Invoice PDF',\n      date: driveData.createdTime || new Date().toISOString(),\n      filename: driveData.name || 'invoice.pdf',\n      pdfText: pdfText\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "3bfcca0c-c5fa-4268-ae2e-9fe17fb83ecc",
      "name": "07 | Code Parse and Enrich Invoice Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1760,
        448
      ],
      "parameters": {
        "jsCode": "const raw = $json.message?.content || $json.text || '{}';\nlet inv;\ntry {\n  inv = JSON.parse(raw);\n} catch(e) {\n  inv = {\n    invoice_number: null,\n    vendor_name: 'Unknown',\n    invoice_date: null,\n    due_date: null,\n    amount_due: null,\n    currency: null,\n    status: 'unclear',\n    line_items_summary: 'Parse error'\n  };\n}\n\nconst prev = $('04 | Code Split PDF Attachments into Items').item.json;\nconst today = new Date();\nconst dueDate = inv.due_date ? new Date(inv.due_date) : null;\nconst isOverdue = dueDate && inv.status === 'unpaid' && dueDate < today;\n\nreturn [{ json: {\n  emailId: prev.emailId,\n  filename: prev.filename,\n  from: prev.from,\n  subject: prev.subject,\n  email_date: prev.date,\n  invoice_number: inv.invoice_number,\n  vendor_name: inv.vendor_name,\n  invoice_date: inv.invoice_date,\n  due_date: inv.due_date,\n  amount_due: inv.amount_due,\n  currency: inv.currency || 'USD',\n  status: inv.status,\n  is_overdue: isOverdue,\n  line_items_summary: inv.line_items_summary,\n  processed_at: new Date().toISOString()\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "3d704d7d-2944-402a-ae32-317a012d4226",
      "name": "08 | Google Sheets Append to Invoice Log",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2128,
        416
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.emailId }}",
            "Notes": "={{ $json.processed_at }}",
            "Keyword": "={{ $json.filename }}",
            "Post Type": "={{ $json.subject }}",
            "Trend Topic": "={{ $json.filename }}",
            "Generated Content": "={{ $json.email_date }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Keyword",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Keyword",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Trend Topic",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Trend Topic",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Post Type",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Post Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Generated Content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Generated Content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Notes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Date"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1zNoiO_ixXR6DaQW2R0yjWURHy_Cj22qNmWQM6cs6Tt4/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1zNoiO_ixXR6DaQW2R0yjWURHy_Cj22qNmWQM6cs6Tt4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1zNoiO_ixXR6DaQW2R0yjWURHy_Cj22qNmWQM6cs6Tt4/edit?usp=drivesdk",
          "cachedResultName": "Content Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "211298d1-ac7d-4346-99fd-b7623c45df6d",
      "name": "10 | Slack Alert Finance on Overdue Invoices",
      "type": "n8n-nodes-base.slack",
      "position": [
        2128,
        640
      ],
      "parameters": {
        "text": "=:warning: *Overdue Invoice Alert*\n\n*Vendor:* {{ $json.vendor_name }}\n*Invoice #:* {{ $json.invoice_number }}\n*Amount Due:* {{ $json.amount_due }} {{ $json.currency }}\n*Due Date:* {{ $json.due_date }}\n*Status:* {{ $json.status.toUpperCase() }}\n\n*Line Items:* {{ $json.line_items_summary }}\n\nPlease review and action immediately.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0ASJMR4MMJ",
          "cachedResultName": "sales-team"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "df1e00e6-09f6-466c-98a7-e2e610ad631c",
      "name": "11 | Code Generate Weekly Summary Stats",
      "type": "n8n-nodes-base.code",
      "position": [
        2144,
        224
      ],
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst total = allItems.length;\nconst paid = allItems.filter(i => i.json.status === 'paid').length;\nconst unpaid = allItems.filter(i => i.json.status === 'unpaid').length;\nconst overdue = allItems.filter(i => i.json.is_overdue).length;\nconst totalAmount = allItems.reduce((sum, i) => sum + (i.json.amount_due || 0), 0);\n\nreturn [{ json: {\n  report_date: new Date().toISOString().split('T')[0],\n  total_invoices: total,\n  paid_count: paid,\n  unpaid_count: unpaid,\n  overdue_count: overdue,\n  total_amount: totalAmount.toFixed(2),\n  summary_text: `Weekly Invoice Report: ${total} invoices processed. Paid: ${paid}, Unpaid: ${unpaid}, Overdue: ${overdue}. Total value: $${totalAmount.toFixed(2)}`\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "462a857b-a73a-45b7-8c4b-cae68f3fdc47",
      "name": "12 | Gmail Email Weekly Report to Finance",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2416,
        224
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=Hi Finance Team,\n\nHere is the weekly invoice reconciliation summary:\n\nTotal Invoices Processed: {{ $json.total_invoices }}\nPaid: {{ $json.paid_count }}\nUnpaid: {{ $json.unpaid_count }}\nOverdue: {{ $json.overdue_count }}\nTotal Value: ${{ $json.total_amount }}\n\nAll invoice data has been logged to the Invoice Tracker Google Sheet.\nOverdue invoices have been flagged in the #finance Slack channel.\n\nBest regards,\nAutomated Finance Bot",
        "options": {},
        "subject": "=Weekly Invoice Reconciliation Report {{ $json.report_date }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "53719b09-efca-451c-86bc-be8e3c83af51",
      "name": "Download file1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        544,
        448
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "2e876e9f-5349-4d06-87f5-b92174bf95be",
      "name": "Extract from File1",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        720,
        448
      ],
      "parameters": {
        "options": {},
        "operation": "pdf"
      },
      "typeVersion": 1.1
    },
    {
      "id": "a819dc84-625a-46c0-9a16-48df8318af59",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1344,
        448
      ],
      "parameters": {
        "text": "=Filename: {{ $json.filename }}\nUploaded by: {{ $json.from }}\nFile date: {{ $json.date }}\n\n--- PDF CONTENT START ---\n{{ $json.pdfText }}\n--- PDF CONTENT END ---\n\nExtract all invoice data from the content above and return it as JSON.",
        "options": {
          "systemMessage": "You are a precise invoice data extraction engine. You will be given the full text content of a PDF invoice along with basic file metadata. Your only job is to extract structured invoice data and return it as valid JSON.\n\nRules:\n- Return ONLY raw JSON. No markdown, no code blocks, no explanation, no preamble.\n- If a field cannot be found or is ambiguous, return null for that field.\n- For status: return \"paid\" if there is clear evidence of payment, \"unpaid\" if an amount is owed, \"unclear\" if you cannot determine.\n- For currency: detect from symbols ($, \u20ac, \u00a3, \u09f3) or written codes (USD, EUR, GBP, BDT). Default to null if not found.\n- For dates: always convert to YYYY-MM-DD format regardless of how they appear in the document.\n- For amount_due: return a plain number only, no currency symbols, no commas. Example: 1500.00\n- For line_items_summary: write a single short sentence describing what was billed. Example: \"3 months of cloud hosting and 1 setup fee.\"\n\nReturn this exact structure:\n{\n  \"invoice_number\": \"<string or null>\",\n  \"vendor_name\": \"<string or null>\",\n  \"invoice_date\": \"<YYYY-MM-DD or null>\",\n  \"due_date\": \"<YYYY-MM-DD or null>\",\n  \"amount_due\": <number or null>,\n  \"currency\": \"<USD|BDT|EUR|GBP or null>\",\n  \"status\": \"paid | unpaid | unclear\",\n  \"line_items_summary\": \"<string or null>\"\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "9d2bcf80-3af7-4c4b-8b92-9e9e9baa4cca",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1376,
        592
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {},
      "typeVersion": 1.3
    },
    {
      "id": "7c549ca7-a008-4493-9de7-f657536064c8",
      "name": "Google Drive Trigger1",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        352,
        448
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "179lkBMnCq6_PqhA9dWzuS6zcXo4Qvijf",
          "cachedResultUrl": "https://drive.google.com/drive/folders/179lkBMnCq6_PqhA9dWzuS6zcXo4Qvijf",
          "cachedResultName": "Inv"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e17559c3-d2c2-44d4-85b4-e1ec53f0d49f",
      "name": "Main Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 928,
        "content": "## \ud83d\udcc4 Invoice Reconciliation\n\nAutomatically extracts data from invoice PDFs dropped in Google Drive, logs every line item, alerts Finance on overdue invoices, and emails a weekly summary report.\n\n**Perfect for:** Finance ops, AP teams, and bookkeepers who need invoice data captured and reconciled without manual entry.\n\n***\n\n## How it works\n\n1. **Google Drive Trigger1** \u00b7 Watches a Drive folder and fires when a new invoice PDF is uploaded.\n2. **Download file1** \u00b7 Downloads the binary PDF content from Drive.\n3. **Extract from File1** \u00b7 Extracts raw text from each PDF page.\n4. **04 | Code Split PDF Attachments into Items** \u00b7 Splits multi invoice PDFs into one n8n item per invoice.\n5. **AI Agent** \u00b7 Reads each invoice text and returns structured fields (vendor, invoice number, amount, due date, line items).\n6. **OpenAI Chat Model** \u00b7 Powers the AI Agent with reasoning over the extracted text.\n7. **07 | Code Parse and Enrich Invoice Data** \u00b7 Normalizes the AI output, computes payment status, and flags overdue items.\n8. **08 | Google Sheets Append to Invoice Log** \u00b7 Appends every invoice as a row in your master log sheet.\n9. **10 | Slack Alert Finance on Overdue Invoices** \u00b7 Posts an alert to the Finance channel for any invoice past its due date.\n10. **11 | Code Generate Weekly Summary Stats** \u00b7 Aggregates the batch into totals, vendor counts, and overdue summaries.\n11. **12 | Gmail Email Weekly Report to Finance** \u00b7 Sends the rolled up summary as a formatted email to Finance leadership.\n\n***\n\n## Setup (~15 minutes)\n\n1. **Google Drive OAuth** \u00b7 Connect Drive in the *Google Drive Trigger1* and *Download file1* nodes, then point the trigger at your invoice intake folder.\n2. **OpenAI API** \u00b7 Add your key in the *OpenAI Chat Model* node and confirm the model supports structured output.\n3. **Google Sheets** \u00b7 Connect the account and map the columns in the *08 | Google Sheets Append to Invoice Log* node to match the AI output schema.\n4. **Slack OAuth** \u00b7 Authorize the workspace and pick the Finance channel in the *10 | Slack Alert Finance on Overdue Invoices* node.\n5. **Gmail OAuth** \u00b7 Connect the sender account and set Finance recipients in the *12 | Gmail Email Weekly Report to Finance* node.\n\n> Works best with text based PDFs. Scanned invoices need OCR upstream of *Extract from File1* or the AI will get garbage text. AI costs scale with invoice text length, so monitor token usage for high volume folders."
      },
      "typeVersion": 1
    },
    {
      "id": "e0bbe443-46ea-4ca7-8e18-ca0ef11e6c4a",
      "name": "Section 1 Intake",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        256,
        288
      ],
      "parameters": {
        "color": 5,
        "width": 776,
        "height": 360,
        "content": "## 1\ufe0f\u20e3 Intake \u00b7 Drive Watch & PDF Download\n\nThe **Google Drive Trigger1** watches an intake folder and fires the workflow each time a new invoice lands. **Download file1** pulls the binary PDF content from Drive, and **Extract from File1** converts the PDF into raw text that downstream nodes can reason over."
      },
      "typeVersion": 1
    },
    {
      "id": "ce2dd24f-55eb-4d98-815c-8ce46e9bf0cc",
      "name": "Section 2 AI Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1056,
        176
      ],
      "parameters": {
        "color": 3,
        "width": 568,
        "height": 552,
        "content": "## 2\ufe0f\u20e3 AI Extraction \u00b7 Structured Invoice Parsing\n\nThe **04 | Code Split PDF Attachments into Items** node splits multi invoice PDFs into one item per invoice so the AI can work on them individually. The **AI Agent**, powered by the **OpenAI Chat Model**, reads each invoice and returns structured fields like vendor, invoice number, total, due date, and line items."
      },
      "typeVersion": 1
    },
    {
      "id": "1c08d744-cd3d-41e6-b6fa-614d10163d48",
      "name": "Section 3 Parse Enrich",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1648,
        176
      ],
      "parameters": {
        "color": 6,
        "width": 360,
        "height": 504,
        "content": "## 3\ufe0f\u20e3 Parse & Enrich \u00b7 Status Calculation\n\nThe **07 | Code Parse and Enrich Invoice Data** node validates the AI output, normalizes dates and currency amounts, computes payment status, and flags invoices that are past their due date. The enriched record fans out to three parallel destinations in the next stage."
      },
      "typeVersion": 1
    },
    {
      "id": "c5c5cdad-14aa-4c2f-86ff-6ef82125582f",
      "name": "Section 4 Output",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2032,
        64
      ],
      "parameters": {
        "color": 4,
        "width": 648,
        "height": 776,
        "content": "## 4\ufe0f\u20e3 Output \u00b7 Log, Alert, and Report\n\nEvery invoice is appended to the master log by **08 | Google Sheets Append to Invoice Log** for audit and reporting. **10 | Slack Alert Finance on Overdue Invoices** posts an instant alert whenever a flagged overdue invoice flows through. **11 | Code Generate Weekly Summary Stats** rolls the batch into totals and vendor counts, which **12 | Gmail Email Weekly Report to Finance** ships to Finance leadership as a formatted summary email."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "07 | Code Parse and Enrich Invoice Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file1": {
      "main": [
        [
          {
            "node": "Extract from File1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File1": {
      "main": [
        [
          {
            "node": "04 | Code Split PDF Attachments into Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive Trigger1": {
      "main": [
        [
          {
            "node": "Download file1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "07 | Code Parse and Enrich Invoice Data": {
      "main": [
        [
          {
            "node": "08 | Google Sheets Append to Invoice Log",
            "type": "main",
            "index": 0
          },
          {
            "node": "11 | Code Generate Weekly Summary Stats",
            "type": "main",
            "index": 0
          },
          {
            "node": "10 | Slack Alert Finance on Overdue Invoices",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "11 | Code Generate Weekly Summary Stats": {
      "main": [
        [
          {
            "node": "12 | Gmail Email Weekly Report to Finance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04 | Code Split PDF Attachments into Items": {
      "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

How it works

Source: https://n8n.io/workflows/15840/ — 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

Automate end-to-end vendor onboarding workflows with an AI-powered autonomous agent built in n8n 🤖. This workflow uses advanced MCTS (Monte Carlo Tree Search) reasoning to intelligently map procuremen

Agent, OpenAI Chat, Google Drive +4
AI & RAG

Automated invoice processing pipeline that extracts data from PDF invoices, uses AI Agent for intelligent expense categorization, generates XML for accounting systems, and routes high-value invoices f

Google Drive Trigger, Google Drive, OpenAI Chat +5
AI & RAG

This workflow automatically converts unstructured internal documentation into clear, actionable Standard Operating Procedures (SOPs).

Google Drive Trigger, Google Drive, Agent +6
AI & RAG

[](https://www.youtube.com/watch?v=T9gnSsjYfvY) &gt; This workflow automatically processes resumes (PDFs) uploaded or updated in a Google Drive folder. It extracts and structures the candidate’s infor

Output Parser Structured, OpenAI Chat, Agent +4
AI & RAG

Who is this for? This template is perfect for agencies, consultancies, freelancers, and project-based teams who want to eliminate repetitive onboarding tasks. If you're tired of manually creating fold

Google Drive Trigger, Google Drive, Slack +5