AutomationFlowsEmail & Gmail › Ai-powered Invoice Data Extraction & Approval Workflow with Scrapegraphai &…

Ai-powered Invoice Data Extraction & Approval Workflow with Scrapegraphai &…

Original n8n title: Ai-powered Invoice Data Extraction & Approval Workflow with Scrapegraphai & Telegram

Byvinci-king-01 @vinci-king-01 on n8n.io

This workflow automatically extracts data from invoice documents (PDFs and images) and processes them through a comprehensive validation and approval system. Multi-Input Triggers - Accepts invoices via email attachments or direct file uploads through webhook. AI-Powered…

Webhook trigger★★★★☆ complexity18 nodesEmail Read ImapN8N Nodes ScrapegraphaiTelegramHTTP Request
Email & Gmail Trigger: Webhook Nodes: 18 Complexity: ★★★★☆ Added:
Ai-powered Invoice Data Extraction & Approval Workflow with Scrapegraphai &… — n8n workflow card showing Email Read Imap, N8N Nodes Scrapegraphai, Telegram integration

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

This workflow follows the Emailreadimap → HTTP Request 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": "VhEwspDqzu7ssFVE",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "My workflow 2",
  "tags": [
    {
      "id": "DxXGubfBzRKh6L8T",
      "name": "Revenue Optimization",
      "createdAt": "2025-07-25T16:24:30.370Z",
      "updatedAt": "2025-07-25T16:24:30.370Z"
    },
    {
      "id": "IxkcJ2IpYIxivoHV",
      "name": "Content Strategy",
      "createdAt": "2025-07-25T12:57:37.677Z",
      "updatedAt": "2025-07-25T12:57:37.677Z"
    },
    {
      "id": "PAKIJ2Mm9EvRcR3u",
      "name": "Trend Monitoring",
      "createdAt": "2025-07-25T12:57:37.670Z",
      "updatedAt": "2025-07-25T12:57:37.670Z"
    },
    {
      "id": "YtfXmaZk44MYedPO",
      "name": "Dynamic Pricing",
      "createdAt": "2025-07-25T16:24:30.369Z",
      "updatedAt": "2025-07-25T16:24:30.369Z"
    },
    {
      "id": "wJ30mjhtrposO8Qt",
      "name": "Simple RAG",
      "createdAt": "2025-07-28T12:55:14.424Z",
      "updatedAt": "2025-07-28T12:55:14.424Z"
    }
  ],
  "nodes": [
    {
      "id": "4d24fd12-5442-4112-b997-2e6b9ece768c",
      "name": "Email Trigger",
      "type": "n8n-nodes-base.emailReadImap",
      "position": [
        1120,
        832
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "b32637a8-8941-4fea-b6cb-b2272d25eaa4",
      "name": "File Upload Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1120,
        1008
      ],
      "parameters": {
        "path": "/invoice-upload",
        "options": {
          "rawBody": true
        },
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "4197b894-434f-42b6-a728-b6773af9b54a",
      "name": "File Processor",
      "type": "n8n-nodes-base.code",
      "position": [
        1424,
        896
      ],
      "parameters": {
        "jsCode": "// Process incoming data from either email or webhook\nconst inputData = $input.all()[0];\nlet invoiceFiles = [];\n\n// Handle email attachments\nif (inputData.json.attachments) {\n  invoiceFiles = inputData.json.attachments\n    .filter(attachment => {\n      const fileName = attachment.filename.toLowerCase();\n      return fileName.endsWith('.pdf') || \n             fileName.endsWith('.png') || \n             fileName.endsWith('.jpg') || \n             fileName.endsWith('.jpeg') ||\n             fileName.endsWith('.tiff') ||\n             fileName.endsWith('.bmp');\n    })\n    .map(attachment => ({\n      filename: attachment.filename,\n      content: attachment.content,\n      contentType: attachment.contentType,\n      source: 'email',\n      sender: inputData.json.from?.text || 'unknown',\n      subject: inputData.json.subject || 'No subject',\n      receivedDate: inputData.json.date || new Date().toISOString()\n    }));\n}\n// Handle direct file uploads\nelse if (inputData.binary) {\n  Object.keys(inputData.binary).forEach(key => {\n    const file = inputData.binary[key];\n    invoiceFiles.push({\n      filename: file.fileName || `upload_${key}`,\n      content: file.data,\n      contentType: file.mimeType,\n      source: 'upload',\n      uploadedDate: new Date().toISOString()\n    });\n  });\n}\n\n// Return each file as separate execution\nreturn invoiceFiles.map((file, index) => ({\n  json: {\n    invoice_id: `INV_${Date.now()}_${index}`,\n    filename: file.filename,\n    source: file.source,\n    sender: file.sender || null,\n    subject: file.subject || null,\n    received_date: file.receivedDate || file.uploadedDate,\n    content_type: file.contentType,\n    processing_status: 'pending',\n    created_at: new Date().toISOString()\n  },\n  binary: {\n    invoice_file: {\n      data: file.content,\n      mimeType: file.contentType,\n      fileName: file.filename\n    }\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "44e738e0-652a-40ff-8a9b-d4d8381771ef",
      "name": "ScrapeGraphAI - Invoice Extractor",
      "type": "n8n-nodes-scrapegraphai.scrapegraphAi",
      "position": [
        1744,
        880
      ],
      "parameters": {
        "resource": "scrapeSmartScraper"
      },
      "typeVersion": 1
    },
    {
      "id": "c891bcd4-df84-4fde-930d-e1eba7f679d0",
      "name": "Data Extractor & Cleaner",
      "type": "n8n-nodes-base.code",
      "position": [
        2080,
        912
      ],
      "parameters": {
        "jsCode": "// Enhanced data extraction and cleaning\nconst inputData = $input.all()[0];\nconst extractedData = inputData.json.result?.invoice_data || {};\nconst originalMetadata = inputData.json;\n\nfunction cleanAndValidateData(data) {\n  // Clean and standardize extracted data\n  const cleaned = {\n    // Basic invoice info\n    invoice_number: cleanString(data.invoice_number),\n    invoice_date: standardizeDate(data.invoice_date),\n    due_date: standardizeDate(data.due_date),\n    \n    // Vendor information\n    vendor: {\n      name: cleanString(data.vendor_name),\n      address: cleanString(data.vendor_address),\n      tax_id: cleanString(data.vendor_tax_id || data.vendor_vat || data.tax_id),\n      email: cleanEmail(data.vendor_email),\n      phone: cleanPhone(data.vendor_phone)\n    },\n    \n    // Bill to information\n    bill_to: {\n      name: cleanString(data.bill_to_name),\n      address: cleanString(data.bill_to_address)\n    },\n    \n    // Financial data\n    currency: (data.currency || 'USD').toUpperCase(),\n    amounts: {\n      subtotal: parseAmount(data.subtotal),\n      tax_total: parseAmount(data.tax_total),\n      discount_amount: parseAmount(data.discount_amount || '0'),\n      shipping_amount: parseAmount(data.shipping_amount || '0'),\n      total_amount: parseAmount(data.total_amount)\n    },\n    \n    // Line items\n    line_items: cleanLineItems(data.line_items || []),\n    \n    // Additional info\n    payment_terms: cleanString(data.payment_terms),\n    purchase_order: cleanString(data.purchase_order),\n    notes: cleanString(data.notes),\n    \n    // Processing metadata\n    processing_info: {\n      extracted_at: new Date().toISOString(),\n      confidence_score: calculateConfidenceScore(data),\n      data_completeness: calculateCompleteness(data)\n    }\n  };\n  \n  return cleaned;\n}\n\nfunction cleanString(str) {\n  if (!str || str === 'null' || str === 'undefined') return null;\n  return str.toString().trim().replace(/\\s+/g, ' ');\n}\n\nfunction standardizeDate(dateStr) {\n  if (!dateStr || dateStr === 'null') return null;\n  try {\n    const date = new Date(dateStr);\n    return date.toISOString().split('T')[0]; // Return YYYY-MM-DD format\n  } catch {\n    return dateStr; // Return original if parsing fails\n  }\n}\n\nfunction cleanEmail(email) {\n  if (!email || email === 'null') return null;\n  const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n  return emailRegex.test(email) ? email.toLowerCase() : null;\n}\n\nfunction cleanPhone(phone) {\n  if (!phone || phone === 'null') return null;\n  return phone.replace(/[^\\d+\\-\\(\\)\\s]/g, '').trim();\n}\n\nfunction parseAmount(amount) {\n  if (!amount || amount === 'null') return 0;\n  const cleaned = amount.toString().replace(/[^\\d.-]/g, '');\n  return parseFloat(cleaned) || 0;\n}\n\nfunction cleanLineItems(items) {\n  if (!Array.isArray(items)) return [];\n  \n  return items.map(item => ({\n    description: cleanString(item.description),\n    quantity: parseFloat(item.quantity) || 1,\n    unit_price: parseAmount(item.unit_price),\n    total: parseAmount(item.total),\n    tax_rate: cleanString(item.tax_rate),\n    tax_amount: parseAmount(item.tax_amount || '0')\n  })).filter(item => item.description); // Remove items without description\n}\n\nfunction calculateConfidenceScore(data) {\n  let score = 0;\n  const requiredFields = ['invoice_number', 'vendor_name', 'total_amount', 'invoice_date'];\n  \n  requiredFields.forEach(field => {\n    if (data[field] && data[field] !== 'null') score += 25;\n  });\n  \n  return score;\n}\n\nfunction calculateCompleteness(data) {\n  const allFields = [\n    'invoice_number', 'invoice_date', 'due_date', 'vendor_name', \n    'vendor_address', 'total_amount', 'subtotal', 'line_items'\n  ];\n  \n  const completedFields = allFields.filter(field => \n    data[field] && data[field] !== 'null' && \n    (Array.isArray(data[field]) ? data[field].length > 0 : true)\n  ).length;\n  \n  return Math.round((completedFields / allFields.length) * 100);\n}\n\nconst cleanedData = cleanAndValidateData(extractedData);\n\nreturn [{\n  json: {\n    ...originalMetadata,\n    extracted_invoice_data: cleanedData,\n    processing_status: 'extracted',\n    updated_at: new Date().toISOString()\n  },\n  binary: inputData.binary // Preserve binary data for potential reprocessing\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "cc08bf61-cb49-4cb5-be64-a9068c7c0486",
      "name": "Validation Rules Engine",
      "type": "n8n-nodes-base.code",
      "position": [
        2400,
        944
      ],
      "parameters": {
        "jsCode": "// Comprehensive validation rules for invoice data\nconst inputData = $input.all()[0];\nconst invoiceData = inputData.json.extracted_invoice_data;\nconst validationResults = {\n  is_valid: true,\n  errors: [],\n  warnings: [],\n  validation_score: 0,\n  business_rules: {\n    duplicate_check: 'pending',\n    amount_threshold: 'pending',\n    vendor_verification: 'pending',\n    date_validation: 'pending'\n  }\n};\n\n// Required field validation\nconst requiredFields = [\n  { field: 'invoice_number', message: 'Invoice number is required' },\n  { field: 'vendor.name', message: 'Vendor name is required' },\n  { field: 'amounts.total_amount', message: 'Total amount is required' },\n  { field: 'invoice_date', message: 'Invoice date is required' }\n];\n\nrequiredFields.forEach(({ field, message }) => {\n  const value = getNestedValue(invoiceData, field);\n  if (!value || value === 0) {\n    validationResults.errors.push(message);\n    validationResults.is_valid = false;\n  } else {\n    validationResults.validation_score += 20;\n  }\n});\n\n// Date validation\nif (invoiceData.invoice_date && invoiceData.due_date) {\n  const invoiceDate = new Date(invoiceData.invoice_date);\n  const dueDate = new Date(invoiceData.due_date);\n  \n  if (dueDate < invoiceDate) {\n    validationResults.errors.push('Due date cannot be before invoice date');\n    validationResults.is_valid = false;\n  } else {\n    validationResults.business_rules.date_validation = 'passed';\n  }\n} else {\n  validationResults.business_rules.date_validation = 'failed';\n}\n\n// Amount validation\nconst amounts = invoiceData.amounts;\nif (amounts) {\n  // Check if total matches calculation\n  const calculatedTotal = amounts.subtotal + amounts.tax_total + amounts.shipping_amount - amounts.discount_amount;\n  const totalDifference = Math.abs(calculatedTotal - amounts.total_amount);\n  \n  if (totalDifference > 0.01) {\n    validationResults.warnings.push(`Total amount mismatch: Expected ${calculatedTotal.toFixed(2)}, got ${amounts.total_amount.toFixed(2)}`);\n  }\n  \n  // Amount threshold check (configurable)\n  const amountThreshold = 10000; // $10,000\n  if (amounts.total_amount > amountThreshold) {\n    validationResults.business_rules.amount_threshold = 'requires_approval';\n    validationResults.warnings.push(`High amount invoice requires additional approval: $${amounts.total_amount}`);\n  } else {\n    validationResults.business_rules.amount_threshold = 'passed';\n  }\n} else {\n  validationResults.errors.push('Amount information is missing');\n  validationResults.is_valid = false;\n}\n\n// Vendor validation\nif (invoiceData.vendor && invoiceData.vendor.name) {\n  // Simulate vendor verification (in real scenario, check against approved vendor list)\n  const approvedVendors = [\n    'ABC Company Ltd', 'XYZ Corporation', 'Tech Solutions Inc', \n    'Office Supplies Co', 'Consulting Partners LLC'\n  ];\n  \n  const isApprovedVendor = approvedVendors.some(vendor => \n    vendor.toLowerCase().includes(invoiceData.vendor.name.toLowerCase()) ||\n    invoiceData.vendor.name.toLowerCase().includes(vendor.toLowerCase())\n  );\n  \n  if (isApprovedVendor) {\n    validationResults.business_rules.vendor_verification = 'approved';\n    validationResults.validation_score += 15;\n  } else {\n    validationResults.business_rules.vendor_verification = 'new_vendor';\n    validationResults.warnings.push('Vendor not in approved list - requires verification');\n  }\n}\n\n// Line items validation\nif (invoiceData.line_items && invoiceData.line_items.length > 0) {\n  let lineItemErrors = [];\n  \n  invoiceData.line_items.forEach((item, index) => {\n    if (!item.description) {\n      lineItemErrors.push(`Line item ${index + 1}: Missing description`);\n    }\n    if (item.quantity <= 0) {\n      lineItemErrors.push(`Line item ${index + 1}: Invalid quantity`);\n    }\n    if (item.unit_price <= 0) {\n      lineItemErrors.push(`Line item ${index + 1}: Invalid unit price`);\n    }\n    \n    // Check line total calculation\n    const expectedTotal = item.quantity * item.unit_price;\n    if (Math.abs(expectedTotal - item.total) > 0.01) {\n      lineItemErrors.push(`Line item ${index + 1}: Total calculation error`);\n    }\n  });\n  \n  if (lineItemErrors.length > 0) {\n    validationResults.warnings.push(...lineItemErrors);\n  } else {\n    validationResults.validation_score += 10;\n  }\n} else {\n  validationResults.warnings.push('No line items found');\n}\n\n// Duplicate invoice check (simulate database lookup)\nif (invoiceData.invoice_number) {\n  // In real scenario, check against database\n  const existingInvoices = ['INV-001', 'INV-002', 'INV-003']; // Mock data\n  \n  if (existingInvoices.includes(invoiceData.invoice_number)) {\n    validationResults.errors.push('Duplicate invoice number detected');\n    validationResults.business_rules.duplicate_check = 'duplicate';\n    validationResults.is_valid = false;\n  } else {\n    validationResults.business_rules.duplicate_check = 'unique';\n    validationResults.validation_score += 15;\n  }\n}\n\n// Calculate confidence level\nlet confidenceLevel = 'low';\nif (validationResults.validation_score >= 80) confidenceLevel = 'high';\nelse if (validationResults.validation_score >= 60) confidenceLevel = 'medium';\n\n// Determine approval requirements\nlet requiresApproval = false;\nlet approvalReason = [];\n\nif (validationResults.business_rules.amount_threshold === 'requires_approval') {\n  requiresApproval = true;\n  approvalReason.push('High amount');\n}\n\nif (validationResults.business_rules.vendor_verification === 'new_vendor') {\n  requiresApproval = true;\n  approvalReason.push('New vendor');\n}\n\nif (validationResults.errors.length > 0) {\n  requiresApproval = true;\n  approvalReason.push('Validation errors');\n}\n\nfunction getNestedValue(obj, path) {\n  return path.split('.').reduce((current, key) => current?.[key], obj);\n}\n\nreturn [{\n  json: {\n    ...inputData.json,\n    validation_results: validationResults,\n    confidence_level: confidenceLevel,\n    requires_approval: requiresApproval,\n    approval_reasons: approvalReason,\n    processing_status: validationResults.is_valid ? 'validated' : 'validation_failed',\n    validated_at: new Date().toISOString()\n  },\n  binary: inputData.binary // Preserve binary data\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "7980050d-408f-4b3a-8e10-fad41c143eff",
      "name": "Approval Required?",
      "type": "n8n-nodes-base.switch",
      "position": [
        2704,
        928
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "",
                    "rightValue": ""
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "8d543b5f-9d0a-48b0-9589-d9c9c5a0adb1",
      "name": "Approval Workflow Generator",
      "type": "n8n-nodes-base.code",
      "position": [
        3008,
        976
      ],
      "parameters": {
        "jsCode": "// Generate approval request with comprehensive details\nconst inputData = $input.all()[0];\nconst invoiceData = inputData.json.extracted_invoice_data;\nconst validation = inputData.json.validation_results;\n\n// Create approval request\nconst approvalRequest = {\n  approval_id: `APPR_${inputData.json.invoice_id}_${Date.now()}`,\n  invoice_id: inputData.json.invoice_id,\n  request_type: 'invoice_approval',\n  priority: determinePriority(inputData.json.approval_reasons),\n  \n  // Invoice summary\n  invoice_summary: {\n    invoice_number: invoiceData.invoice_number,\n    vendor_name: invoiceData.vendor ? invoiceData.vendor.name : 'Unknown',\n    total_amount: invoiceData.amounts ? invoiceData.amounts.total_amount : 0,\n    currency: invoiceData.currency,\n    invoice_date: invoiceData.invoice_date,\n    due_date: invoiceData.due_date\n  },\n  \n  // Approval details\n  approval_reasons: inputData.json.approval_reasons,\n  validation_score: validation.validation_score,\n  confidence_level: inputData.json.confidence_level,\n  \n  // Issues requiring attention\n  attention_required: {\n    errors: validation.errors,\n    warnings: validation.warnings,\n    business_rule_flags: Object.entries(validation.business_rules)\n      .filter(([key, value]) => value === 'requires_approval' || value === 'failed')\n      .map(([key, value]) => ({ rule: key, status: value }))\n  },\n  \n  // Approval workflow\n  workflow_steps: generateApprovalSteps(inputData.json.approval_reasons, invoiceData.amounts ? invoiceData.amounts.total_amount : 0),\n  \n  // Request metadata\n  requested_at: new Date().toISOString(),\n  requested_by: 'system',\n  status: 'pending_approval',\n  \n  // Generate approval message\n  approval_message: generateApprovalMessage(invoiceData, validation, inputData.json.approval_reasons)\n};\n\nfunction determinePriority(reasons) {\n  if (reasons.includes('Validation errors')) return 'high';\n  if (reasons.includes('High amount')) return 'medium';\n  return 'normal';\n}\n\nfunction generateApprovalSteps(reasons, amount) {\n  const steps = [];\n  \n  // Finance team review for high amounts\n  if (amount > 10000) {\n    steps.push({\n      step: 1,\n      approver_role: 'finance_manager',\n      required: true,\n      description: 'Finance manager approval for high-value invoice'\n    });\n  }\n  \n  // Procurement review for new vendors\n  if (reasons.includes('New vendor')) {\n    steps.push({\n      step: steps.length + 1,\n      approver_role: 'procurement_manager',\n      required: true,\n      description: 'Procurement verification for new vendor'\n    });\n  }\n  \n  // Department head approval\n  steps.push({\n    step: steps.length + 1,\n    approver_role: 'department_head',\n    required: true,\n    description: 'Department head final approval'\n  });\n  \n  return steps;\n}\n\nfunction generateApprovalMessage(invoiceData, validation, reasons) {\n  let message = `\ud83e\uddfe **INVOICE APPROVAL REQUEST**\\n\\n`;\n  message += `\ud83d\udccb **Invoice:** ${invoiceData.invoice_number || 'N/A'}\\n`;\n  message += `\ud83c\udfe2 **Vendor:** ${invoiceData.vendor ? invoiceData.vendor.name : 'Unknown'}\\n`;\n  \n  const amount = invoiceData.amounts ? invoiceData.amounts.total_amount : 0;\n  const currency = invoiceData.currency || 'USD';\n  message += `\ud83d\udcb0 **Amount:** ${currency} ${amount.toLocaleString()}\\n`;\n  message += `\ud83d\udcc5 **Date:** ${invoiceData.invoice_date || 'N/A'}\\n`;\n  message += `\u23f0 **Due:** ${invoiceData.due_date || 'N/A'}\\n\\n`;\n  \n  message += `\ud83d\udea8 **Approval Required For:**\\n`;\n  reasons.forEach(reason => {\n    message += `\u2022 ${reason}\\n`;\n  });\n  \n  if (validation.errors.length > 0) {\n    message += `\\n\u274c **Errors:**\\n`;\n    validation.errors.forEach(error => {\n      message += `\u2022 ${error}\\n`;\n    });\n  }\n  \n  if (validation.warnings.length > 0) {\n    message += `\\n\u26a0\ufe0f **Warnings:**\\n`;\n    validation.warnings.forEach(warning => {\n      message += `\u2022 ${warning}\\n`;\n    });\n  }\n  \n  message += `\\n\ud83d\udcca **Validation Score:** ${validation.validation_score}/100\\n`;\n  message += `\ud83c\udfaf **Confidence:** ${inputData.json.confidence_level.toUpperCase()}\\n\\n`;\n  message += `Please review and approve/reject this invoice.`;\n  \n  return message;\n}\n\nreturn [{\n  json: {\n    ...inputData.json,\n    approval_request: approvalRequest,\n    processing_status: 'pending_approval',\n    updated_at: new Date().toISOString()\n  },\n  binary: inputData.binary // Preserve binary data\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "92ee2ffa-df6f-447c-bc74-bc78a40e90bf",
      "name": "Approval Notification",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3360,
        912
      ],
      "parameters": {
        "text": "={{ $json.approval_request.approval_message }}",
        "chatId": "@invoice_approvals",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e2f6f5d5-a8b8-41df-8113-f45242fa2c9f",
      "name": "Accounting System Integration",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3584,
        912
      ],
      "parameters": {
        "url": "https://your-accounting-system.com/api/invoices",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "invoice_data",
              "value": "={{ JSON.stringify($json.extracted_invoice_data) }}"
            },
            {
              "name": "validation_results",
              "value": "={{ JSON.stringify($json.validation_results) }}"
            },
            {
              "name": "processing_metadata",
              "value": "={{ JSON.stringify({ invoice_id: $json.invoice_id, source: $json.source, processed_at: $json.updated_at }) }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "httpHeaderAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "ffadff50-4b5e-4cf0-ad78-3f43b3ab9237",
      "name": "Sticky Note - Triggers",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        -32
      ],
      "parameters": {
        "color": 2,
        "width": 320,
        "height": 1202,
        "content": "# Step 1: Multi-Input Triggers \ud83d\udce7\ud83d\udcc1\n\n**Flexible Invoice Reception**\n\nTwo trigger options for maximum flexibility:\n\n## Email Trigger:\n- **Purpose**: Automatic processing of emailed invoices\n- **Supported**: PDF, PNG, JPG, JPEG, TIFF, BMP\n- **Features**: Attachment filtering, sender tracking\n- **Polling**: Every 30 seconds\n\n## File Upload Webhook:\n- **Purpose**: Direct file upload processing\n- **Endpoint**: `/invoice-upload`\n- **Method**: POST with file data\n- **Use Case**: Manual uploads, API integrations\n\n## Benefits:\n- Multiple intake channels\n- Automatic file type detection\n- Metadata preservation\n- Source tracking for audit trails"
      },
      "typeVersion": 1
    },
    {
      "id": "3a13dfe2-a654-434f-b8e0-91ddb685b7c3",
      "name": "Sticky Note - File Processor",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        -32
      ],
      "parameters": {
        "color": 3,
        "width": 320,
        "height": 1202,
        "content": "# Step 2: File Processing \ud83d\udd04\n\n**Smart File Handler**\n\nProcesses incoming files from multiple sources with intelligent routing.\n\n## Key Features:\n- **Multi-source Support**: Email attachments + direct uploads\n- **File Type Validation**: PDF, images only\n- **Metadata Extraction**: Sender, subject, timestamps\n- **Unique ID Generation**: Trackable invoice IDs\n\n## Processing Logic:\n- Filters supported file types\n- Extracts source information\n- Creates processing metadata\n- Prepares for AI extraction\n\n## Output:\n- Clean file objects\n- Processing metadata\n- Binary file data for AI analysis"
      },
      "typeVersion": 1
    },
    {
      "id": "74fde2b5-236f-4e42-a98b-d1a7c43bc9ae",
      "name": "Sticky Note - AI Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1664,
        -32
      ],
      "parameters": {
        "color": 4,
        "width": 320,
        "height": 1202,
        "content": "# Step 3: AI Invoice Extraction \ud83e\udd16\n\n**ScrapeGraphAI-Powered Data Extraction**\n\nAdvanced AI extraction of invoice data from PDFs and images.\n\n## Extraction Capabilities:\n- **Basic Info**: Invoice #, dates, amounts\n- **Vendor Details**: Name, address, contact info\n- **Line Items**: Description, qty, price, tax\n- **Financial Data**: Subtotals, taxes, totals\n- **Additional**: PO numbers, terms, notes\n\n## AI Features:\n- Multi-format support (PDF, images)\n- OCR for scanned documents\n- Structured JSON output\n- High accuracy extraction\n\n## Benefits:\n- Eliminates manual data entry\n- Handles various invoice formats\n- Consistent data structure\n- Scalable processing"
      },
      "typeVersion": 1
    },
    {
      "id": "6f42014e-fe4b-4424-9a29-e73f1fc4575f",
      "name": "Sticky Note - Data Cleaning",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        -32
      ],
      "parameters": {
        "color": 5,
        "width": 320,
        "height": 1202,
        "content": "# Step 4: Data Cleaning & Enhancement \ud83e\uddf9\n\n**Advanced Data Processing**\n\nCleans and standardizes extracted data for business use.\n\n## Data Cleaning:\n- **Format Standardization**: Dates, amounts, text\n- **Validation**: Email formats, phone numbers\n- **Null Handling**: Missing data management\n- **Type Conversion**: String to numeric conversion\n\n## Enhancement Features:\n- **Confidence Scoring**: Data quality assessment\n- **Completeness Analysis**: Missing field detection\n- **Line Item Processing**: Individual item validation\n- **Metadata Addition**: Processing timestamps\n\n## Quality Assurance:\n- Removes invalid entries\n- Standardizes formats\n- Calculates data reliability\n- Prepares for validation"
      },
      "typeVersion": 1
    },
    {
      "id": "3950a900-13c8-4aa5-b128-e9397220ab52",
      "name": "Sticky Note - Validation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2304,
        -32
      ],
      "parameters": {
        "color": 6,
        "width": 320,
        "height": 1202,
        "content": "# Step 5: Business Rules Validation \u2705\n\n**Comprehensive Validation Engine**\n\nApplies business rules and validation logic to ensure data quality.\n\n## Validation Types:\n- **Required Fields**: Critical data presence\n- **Data Integrity**: Amount calculations, date logic\n- **Business Rules**: Vendor approval, amount thresholds\n- **Duplicate Detection**: Invoice number uniqueness\n\n## Validation Results:\n- **Errors**: Critical issues blocking processing\n- **Warnings**: Non-critical issues requiring attention\n- **Scores**: Overall validation quality (0-100)\n- **Business Flags**: Rule-specific status\n\n## Advanced Features:\n- Configurable thresholds\n- Vendor whitelist checking\n- Amount calculation verification\n- Approval requirement detection"
      },
      "typeVersion": 1
    },
    {
      "id": "daf3f597-b104-4c4c-abaf-5363f982a7a0",
      "name": "Sticky Note - Approval Routing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2624,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 1202,
        "content": "# Step 6: Approval Routing \ud83d\udd00\n\n**Intelligent Decision Engine**\n\nRoutes invoices based on validation results and business rules.\n\n## Routing Logic:\n- **Auto-Process**: Clean invoices \u2192 Direct to accounting\n- **Approval Required**: Flagged invoices \u2192 Approval workflow\n- **Error Handling**: Invalid invoices \u2192 Manual review\n\n## Approval Triggers:\n- High amount thresholds\n- New/unverified vendors\n- Validation errors/warnings\n- Data quality issues\n\n## Benefits:\n- Automated decision making\n- Exception handling\n- Compliance enforcement\n- Workflow optimization\n\n## Efficiency:\n- Reduces manual review\n- Focuses attention on exceptions\n- Maintains audit trails\n- Ensures policy compliance"
      },
      "typeVersion": 1
    },
    {
      "id": "b0e3beae-27ec-4543-8be6-b68b3c8ef89d",
      "name": "Sticky Note - Approval Workflow",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2944,
        -32
      ],
      "parameters": {
        "width": 320,
        "height": 1202,
        "content": "# Step 7: Approval Workflow \ud83d\udc65\n\n**Multi-Stage Approval Process**\n\nGenerates structured approval requests with comprehensive details.\n\n## Approval Features:\n- **Priority Classification**: High/Medium/Normal\n- **Multi-stage Workflow**: Role-based approvals\n- **Detailed Context**: All validation results\n- **Interactive Notifications**: Telegram with buttons\n\n## Approval Stages:\n1. **Finance Manager**: High-value invoices\n2. **Procurement**: New vendor verification\n3. **Department Head**: Final approval\n\n## Rich Context:\n- Invoice summary\n- Validation issues\n- Business rule flags\n- Approval reasoning\n\n## User Experience:\n- Clear approval messages\n- One-click approve/reject\n- Detailed invoice preview\n- Audit trail maintenance"
      },
      "typeVersion": 1
    },
    {
      "id": "cd228530-faa8-4685-a2dd-505ca1d2d2ff",
      "name": "Sticky Note - System Integration",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3264,
        -32
      ],
      "parameters": {
        "color": 4,
        "width": 544,
        "height": 1202,
        "content": "# Step 8: System Integration \ud83d\udd17\n\n**Seamless Accounting Integration**\n\nDirect integration with accounting systems for automated processing.\n\n## Integration Features:\n- **API-Based**: RESTful API integration\n- **Structured Data**: Clean JSON payload\n- **Metadata Included**: Processing context\n- **Error Handling**: Retry logic and logging\n\n## Data Payload:\n- Complete invoice data\n- Validation results\n- Processing metadata\n- Audit information\n\n## Supported Systems:\n- QuickBooks\n- SAP\n- NetSuite\n- Xero\n- Custom ERP systems\n\n## Benefits:\n- Eliminates double entry\n- Real-time processing\n- Data consistency\n- Automated reconciliation\n- Audit trail preservation"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7e6fed6c-3ee0-42af-988e-fb8c404015b5",
  "connections": {
    "Email Trigger": {
      "main": [
        [
          {
            "node": "File Processor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "File Processor": {
      "main": [
        [
          {
            "node": "ScrapeGraphAI - Invoice Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Required?": {
      "main": [
        [
          {
            "node": "Approval Workflow Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "File Upload Webhook": {
      "main": [
        [
          {
            "node": "File Processor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Notification": {
      "main": [
        [
          {
            "node": "Accounting System Integration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validation Rules Engine": {
      "main": [
        [
          {
            "node": "Approval Required?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Extractor & Cleaner": {
      "main": [
        [
          {
            "node": "Validation Rules Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approval Workflow Generator": {
      "main": [
        [
          {
            "node": "Approval Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ScrapeGraphAI - Invoice Extractor": {
      "main": [
        [
          {
            "node": "Data Extractor & Cleaner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automatically extracts data from invoice documents (PDFs and images) and processes them through a comprehensive validation and approval system. Multi-Input Triggers - Accepts invoices via email attachments or direct file uploads through webhook. AI-Powered…

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

More Email & Gmail workflows → · Browse all categories →

Related workflows

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

Email & Gmail

Transform your customer support operations with this enterprise-grade automation workflow that unifies, categorizes, and intelligently routes support tickets from multiple channels.

Email Read Imap, Email Send, Slack +1
Email & Gmail

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 78 nodes.

Email Read Imap, Email Send, HTTP Request +2
Email & Gmail

Receive booking requests via webhook with automatic validation, duplicate detection, availability checking, confirmation emails, Google Calendar sync, and Slack notifications.

HTTP Request, Gmail, Google Calendar +2
Email & Gmail

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 26 nodes.

Email Read Imap, Email Send, HTTP Request +1
Email & Gmail

Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 26 nodes.

Email Read Imap, Email Send, HTTP Request +1