{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "8c8ca031-b331-45e8-954a-67256d21895d",
      "name": "Sticky_Intake",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        256,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 466,
        "height": 330,
        "content": "## \ud83d\udce5 PHASE 1: Intake & Validation\nTriggers on Gmail attachments. Validates PDF format, filters out non-invoice emails, and performs initial data quality checks."
      },
      "typeVersion": 1
    },
    {
      "id": "41d5378a-b652-4229-94a0-ba00dcd853e1",
      "name": "Sticky_Parsing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 550,
        "height": 362,
        "content": "## \ud83d\udd2c PHASE 2: AI Parsing & Extraction\n**Parse PDF to JSON:** Converts binary PDF to structured data. **AI Ledger Mapper:** Extracts financial fields with intelligent pattern matching and confidence scoring."
      },
      "typeVersion": 1
    },
    {
      "id": "69631f3b-3285-49ac-80e1-364df5c6c6d1",
      "name": "Sticky_Sync",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1312,
        -368
      ],
      "parameters": {
        "color": 7,
        "width": 650,
        "height": 650,
        "content": "## \ud83d\ude80 PHASE 3: Ledger Sync & Archival\nUpdates Google Sheets ledger, creates Airtable records, archives to Drive. High-value or low-confidence items trigger Slack escalations for manual review."
      },
      "typeVersion": 1
    },
    {
      "id": "69ed7655-68d0-4266-beab-2c715f24f648",
      "name": "Sticky_ReviewQueue",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1312,
        352
      ],
      "parameters": {
        "color": 7,
        "width": 578,
        "height": 350,
        "content": "## \u26a0\ufe0f PHASE 4: Review Queue\nLow confidence scores (<0.7) or high-value invoices (>$5000) require manual approval before final posting."
      },
      "typeVersion": 1
    },
    {
      "id": "23803aa6-c52d-4c26-a617-4e979a82d69f",
      "name": "Gmail: Watch Invoices",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        320,
        -64
      ],
      "parameters": {},
      "typeVersion": 2
    },
    {
      "id": "8d464849-1f13-4476-a6d8-aca8768f5e65",
      "name": "IF: Valid PDF Attachment",
      "type": "n8n-nodes-base.if",
      "position": [
        480,
        -64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "array",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.attachments }}",
              "rightValue": ""
            },
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.attachments[0].mimeType }}",
              "rightValue": "application/pdf"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9ceec5e8-db65-45fc-8a25-113ccab7f9de",
      "name": "Code: Pre-Processor",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        -64
      ],
      "parameters": {
        "jsCode": "// Code Node: Pre-Processing & Metadata\nconst items = $input.all();\n\nreturn items.map(item => {\n    const attachment = item.json.attachments[0];\n    \n    // Extract email metadata\n    item.json.emailSubject = item.json.subject || '';\n    item.json.senderEmail = item.json.from?.address || 'user@example.com';\n    item.json.senderName = item.json.from?.name || 'Unknown Sender';\n    item.json.receivedDate = item.json.date || new Date().toISOString();\n    item.json.gmailMessageId = item.json.id || '';\n    \n    // Attachment metadata\n    item.json.attachmentName = attachment.name;\n    item.json.attachmentSize = attachment.size || 0;\n    item.json.attachmentMimeType = attachment.mimeType;\n    \n    // Generate processing ID\n    item.json.processingId = `INV-${Date.now()}-${Math.random().toString(36).substring(2, 8).toUpperCase()}`;\n    item.json.intakeTimestamp = new Date().toISOString();\n    \n    return item;\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "46fec074-98c4-4b8b-814f-d7609ce7619f",
      "name": "HTML to PDF: Parse to JSON",
      "type": "n8n-nodes-htmlcsstopdf.htmlcsstopdf",
      "position": [
        816,
        -64
      ],
      "parameters": {
        "resource": "pdfManipulation",
        "operation": "parsePdfToJson"
      },
      "credentials": {
        "htmlcsstopdfApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "01d6530b-1b4b-45df-a9ca-39457bd9a87c",
      "name": "Code: AI Ledger Mapper",
      "type": "n8n-nodes-base.code",
      "position": [
        976,
        -64
      ],
      "parameters": {
        "jsCode": "// Code Node: AI-Powered Financial Data Extraction\nconst item = $input.first();\nconst text = item.json.text || '';\nconst lines = text.split('\\n');\n\n// Enhanced pattern matching for invoice fields\nconst patterns = {\n    // Amount patterns\n    total: [\n        /(?:total|amount due|balance due|grand total)[:\\s]*\\$?([0-9,]+\\.\\d{2})/i,\n        /(?:total)[:\\s]*([0-9,]+\\.\\d{2})/i,\n        /\\$([0-9,]+\\.\\d{2})(?:\\s*(?:total|due))/i\n    ],\n    \n    // Tax patterns\n    tax: [\n        /(?:tax|vat|gst|sales tax)[:\\s]*\\$?([0-9,]+\\.\\d{2})/i,\n        /(?:tax amount)[:\\s]*([0-9,]+\\.\\d{2})/i\n    ],\n    \n    // Vendor patterns\n    vendor: [\n        /(?:from|vendor|supplier|bill from)[:\\s]*([A-Za-z0-9\\s&\\.,'\\-]+?)(?:\\n|$)/i,\n        /^([A-Z][A-Za-z0-9\\s&\\.,'\\-]{3,40})$/m,  // Company name at start of line\n        /(?:payable to)[:\\s]*([A-Za-z0-9\\s&\\.,'\\-]+)/i\n    ],\n    \n    // Invoice number patterns\n    invoiceNumber: [\n        /(?:invoice|inv|bill)(?:\\s*#|\\s*no\\.?|\\s*number)[:\\s]*([A-Z0-9\\-]+)/i,\n        /#([A-Z0-9\\-]{3,20})/\n    ],\n    \n    // Date patterns\n    invoiceDate: [\n        /(?:invoice date|date|issued)[:\\s]*(\\d{1,2}[/-]\\d{1,2}[/-]\\d{2,4})/i,\n        /(\\d{1,2}\\/\\d{1,2}\\/\\d{2,4})/\n    ],\n    \n    // Due date patterns\n    dueDate: [\n        /(?:due date|payment due)[:\\s]*(\\d{1,2}[/-]\\d{1,2}[/-]\\d{2,4})/i\n    ],\n    \n    // Subtotal patterns\n    subtotal: [\n        /(?:subtotal|sub-total)[:\\s]*\\$?([0-9,]+\\.\\d{2})/i\n    ]\n};\n\n// Function to try multiple patterns\nfunction extractField(patterns, text) {\n    for (const pattern of patterns) {\n        const match = text.match(pattern);\n        if (match && match[1]) {\n            return match[1].trim();\n        }\n    }\n    return null;\n}\n\n// Extract all fields\nconst totalStr = extractField(patterns.total, text);\nconst taxStr = extractField(patterns.tax, text);\nconst subtotalStr = extractField(patterns.subtotal, text);\nconst vendorRaw = extractField(patterns.vendor, text);\nconst invoiceNumber = extractField(patterns.invoiceNumber, text);\nconst invoiceDate = extractField(patterns.invoiceDate, text);\nconst dueDate = extractField(patterns.dueDate, text);\n\n// Parse amounts\nconst totalAmount = totalStr ? parseFloat(totalStr.replace(/[,$]/g, '')) : 0;\nconst taxAmount = taxStr ? parseFloat(taxStr.replace(/[,$]/g, '')) : 0;\nconst subtotalAmount = subtotalStr ? parseFloat(subtotalStr.replace(/[,$]/g, '')) : (totalAmount - taxAmount);\n\n// Clean vendor name\nconst vendorName = vendorRaw ? vendorRaw.replace(/[\\n\\r]/g, ' ').trim().substring(0, 100) : 'Unknown Vendor';\n\n// Calculate confidence score\nlet confidence = 0;\nlet confidenceFactors = [];\n\nif (totalAmount > 0) {\n    confidence += 0.4;\n    confidenceFactors.push('amount_found');\n}\nif (vendorRaw && vendorRaw.length > 3) {\n    confidence += 0.3;\n    confidenceFactors.push('vendor_found');\n}\nif (invoiceNumber) {\n    confidence += 0.15;\n    confidenceFactors.push('invoice_number_found');\n}\nif (taxAmount > 0) {\n    confidence += 0.1;\n    confidenceFactors.push('tax_found');\n}\nif (invoiceDate) {\n    confidence += 0.05;\n    confidenceFactors.push('date_found');\n}\n\n// Validation checks\nconst isValidAmount = totalAmount > 0 && totalAmount < 1000000;\nconst isValidVendor = vendorName !== 'Unknown Vendor' && vendorName.length > 2;\nconst mathCheck = Math.abs((subtotalAmount + taxAmount) - totalAmount) < 1; // Allow $1 rounding\n\nif (mathCheck) {\n    confidence += 0.05;\n    confidenceFactors.push('math_verified');\n}\n\n// Build structured output\nitem.json.extracted = {\n    vendorName: vendorName,\n    totalAmount: totalAmount,\n    taxAmount: taxAmount,\n    subtotalAmount: subtotalAmount,\n    invoiceNumber: invoiceNumber || 'NOT_FOUND',\n    invoiceDate: invoiceDate || item.json.receivedDate?.split('T')[0] || '',\n    dueDate: dueDate || '',\n    confidence: Math.min(confidence, 0.99),\n    confidenceFactors: confidenceFactors,\n    validationStatus: isValidAmount && isValidVendor ? 'PASS' : 'REVIEW_REQUIRED',\n    extractedAt: new Date().toISOString(),\n    rawTextLength: text.length\n};\n\n// Flatten for easier access\nitem.json.vendorName = vendorName;\nitem.json.totalAmount = totalAmount;\nitem.json.taxAmount = taxAmount;\nitem.json.subtotalAmount = subtotalAmount;\nitem.json.invoiceNumber = invoiceNumber || 'NOT_FOUND';\nitem.json.invoiceDate = invoiceDate || item.json.receivedDate?.split('T')[0] || '';\nitem.json.dueDate = dueDate || '';\nitem.json.confidence = item.json.extracted.confidence;\nitem.json.validationStatus = item.json.extracted.validationStatus;\n\n// Categorization\nif (totalAmount > 5000) {\n    item.json.category = 'HIGH_VALUE';\n} else if (totalAmount > 1000) {\n    item.json.category = 'MEDIUM_VALUE';\n} else {\n    item.json.category = 'LOW_VALUE';\n}\n\n// Risk flag\nitem.json.requiresReview = confidence < 0.7 || totalAmount > 5000;\n\nreturn item;"
      },
      "typeVersion": 2
    },
    {
      "id": "2f7df52f-a24c-4323-b275-9b2faf4f83ed",
      "name": "IF: Auto-Approve",
      "type": "n8n-nodes-base.if",
      "position": [
        1136,
        -64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.requiresReview }}",
              "rightValue": false
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9ed956df-b1a5-4756-91e7-b2fb13354242",
      "name": "Google Sheets: Add Row",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1424,
        -240
      ],
      "parameters": {
        "columns": {
          "value": {
            "Category": "={{ $json.category }}",
            "Due Date": "={{ $json.dueDate }}",
            "Subtotal": "={{ $json.subtotalAmount }}",
            "Tax Amount": "={{ $json.taxAmount }}",
            "Sender Name": "={{ $json.senderName }}",
            "Vendor Name": "={{ $json.vendorName }}",
            "Invoice Date": "={{ $json.invoiceDate }}",
            "Processed At": "={{ $json.extractedAt }}",
            "Sender Email": "={{ $json.senderEmail }}",
            "Total Amount": "={{ $json.totalAmount }}",
            "Processing ID": "={{ $json.processingId }}",
            "Received Date": "={{ $json.receivedDate }}",
            "Invoice Number": "={{ $json.invoiceNumber }}",
            "Confidence Score": "={{ $json.confidence }}",
            "Gmail Message ID": "={{ $json.gmailMessageId }}",
            "Validation Status": "={{ $json.validationStatus }}"
          },
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID",
          "cachedResultName": "Invoice Ledger"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "17a425a2-a110-4798-b4fc-b307be2ec658",
      "name": "Airtable: Create Record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1424,
        -80
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_BASE_ID",
          "cachedResultName": "Invoice Processing"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "Invoices",
          "cachedResultName": "Invoices"
        },
        "options": {},
        "operation": "create"
      },
      "typeVersion": 2
    },
    {
      "id": "45f0dd21-60cb-4542-9d07-30114e2a69c1",
      "name": "Google Drive: Archive Invoice",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1424,
        80
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "INVOICE_ARCHIVE_FOLDER_ID",
          "cachedResultName": "Invoice Archive"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "4f5a2de1-9ad5-4e10-bc0a-c0f774ee9789",
      "name": "Slack: Success Notification",
      "type": "n8n-nodes-base.slack",
      "position": [
        1632,
        -48
      ],
      "parameters": {
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "95f9207e-2c14-40fc-a2e2-61ebff886a3f",
      "name": "Slack: Review Required",
      "type": "n8n-nodes-base.slack",
      "position": [
        1360,
        464
      ],
      "parameters": {
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "72e9a7e4-5a64-4068-9da5-c3af5ee35751",
      "name": "Google Sheets: Review Queue",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1552,
        480
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "PENDING_REVIEW",
            "Category": "={{ $json.category }}",
            "Confidence": "={{ $json.confidence }}",
            "Flagged At": "={{ $now.toISO() }}",
            "Vendor Name": "={{ $json.vendorName }}",
            "Total Amount": "={{ $json.totalAmount }}",
            "Processing ID": "={{ $json.processingId }}",
            "Review Reason": "={{ $json.confidence < 0.7 ? 'Low Confidence' : 'High Value' }}",
            "Gmail Message ID": "={{ $json.gmailMessageId }}"
          },
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=1",
          "cachedResultName": "Review Queue"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID",
          "cachedResultName": "Invoice Ledger"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "23726aef-e060-43f0-8786-516092fd7bc0",
      "name": "Gmail: Review Alert",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1728,
        464
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=**INVOICE PENDING MANUAL REVIEW**\n\nAn invoice has been flagged for review due to {{ $json.confidence < 0.7 ? 'low confidence score' : 'high value' }}.\n\n**Invoice Details:**\n- Processing ID: {{ $json.processingId }}\n- Vendor: {{ $json.vendorName }}\n- Invoice Number: {{ $json.invoiceNumber }}\n- Date: {{ $json.invoiceDate }}\n- Total Amount: ${{ $json.totalAmount.toFixed(2) }}\n- Tax: ${{ $json.taxAmount.toFixed(2) }}\n- Confidence Score: {{ ($json.confidence * 100).toFixed(1) }}%\n\n**Sender Information:**\n- From: {{ $json.senderName }} ({{ $json.senderEmail }})\n- Received: {{ $json.receivedDate }}\n\n**Action Required:**\nPlease review the original email in Gmail (Message ID: {{ $json.gmailMessageId }}) and verify the extracted data.\n\nOnce reviewed, update the status in the Review Queue sheet.\n\n---\nAutomated Invoice Processing System",
        "options": {
          "ccList": "user@example.com",
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          }
        },
        "subject": "=Invoice Review Required: {{ $json.vendorName }} - ${{ $json.totalAmount }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "f04e30d3-7349-4042-9832-5d06d54d1244",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -272,
        -992
      ],
      "parameters": {
        "width": 448,
        "height": 704,
        "content": "## \ud83d\udcb0 Autonomous Invoice Extraction Hub (v11.0)\n\nIndustrial-grade pipeline for automated financial data entry: Gmail \u2192 JSON Parsing \u2192 AI Ledger Mapping \u2192 Multi-Tier Sync.\n\n### \u2699\ufe0f Core Sovereign Logic\n* **PHASE 1: Intake & Validation:** Monitors Gmail for PDF attachments and performs binary integrity checks.\n* **PHASE 2: AI Parsing:** Uses **HTML to PDF (Parse)** to convert unstructured PDF data into structured JSON objects.\n* **PHASE 3: Intelligence Mapping:** Custom Code Node extracts Vendor, Total, Tax, and Due Date with pattern-matching confidence scoring.\n* **PHASE 4: Auto-Approval Gating:** - **Green Path:** Confidence > 0.7 & Value < $5k \u2192 Auto-posts to Sheets/Airtable.\n    - **Amber Path:** Low confidence or high value \u2192 Diverts to Review Queue & Slack Alert.\n* **PHASE 5: Compliance Archival:** Vaults original invoices in Google Drive with forensic metadata.\n\n### \ud83d\udccb Setup & Prerequisites\n1. **Compulsory Node:** **HTML to PDF (Parse)** for data atomization.\n2. **Targets:** Set your Google Sheet ID (Ledger & Review tabs) and Airtable Base.\n3. **Alerts:** Configure Slack Webhook for manual review escalations.\n\n**Metrics:** `Extraction_Confidence`, `Tax_Variance`, `Approval_Latency`."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "IF: Auto-Approve": {
      "main": [
        [
          {
            "node": "Google Sheets: Add Row",
            "type": "main",
            "index": 0
          },
          {
            "node": "Airtable: Create Record",
            "type": "main",
            "index": 0
          },
          {
            "node": "Google Drive: Archive Invoice",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack: Review Required",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Pre-Processor": {
      "main": [
        [
          {
            "node": "HTML to PDF: Parse to JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: AI Ledger Mapper": {
      "main": [
        [
          {
            "node": "IF: Auto-Approve",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Review Required": {
      "main": [
        [
          {
            "node": "Google Sheets: Review Queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Valid PDF Attachment": {
      "main": [
        [
          {
            "node": "Code: Pre-Processor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTML to PDF: Parse to JSON": {
      "main": [
        [
          {
            "node": "Code: AI Ledger Mapper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets: Review Queue": {
      "main": [
        [
          {
            "node": "Gmail: Review Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive: Archive Invoice": {
      "main": [
        [
          {
            "node": "Slack: Success Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}