請常常用システムは提出のために使用されます

上級

これはInvoice Processing, AI Summarization分野の自動化ワークフローで、24個のノードを含みます。主にIf, Code, Xero, Gmail, Slackなどのノードを使用。 Gmail、OCR.space、Slack、および Xero を用いた請求書処理の自動化

前提条件
  • Googleアカウント + Gmail API認証情報
  • Slack Bot Token または Webhook URL
  • ターゲットAPIの認証情報が必要な場合あり
  • Google Sheets API認証情報
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "id": "QHTTTSIjepK3ipPO",
  "meta": {
    "instanceId": "a9990cea8ba499cd2caa870c8ec5e719a88b31e6ed62907b6084053e5dc1857a",
    "templateCredsSetupCompleted": true
  },
  "name": "Invoice Processing System for submission",
  "tags": [
    {
      "id": "CMJL1dF3mMlRu0Jb",
      "name": "Invoice Processing",
      "createdAt": "2025-10-11T20:13:04.997Z",
      "updatedAt": "2025-10-11T20:13:04.997Z"
    }
  ],
  "nodes": [
    {
      "id": "189e9199-b377-4acc-a0e7-d5769e69a762",
      "name": "Gmailトリガー",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -96,
        16
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "has:attachment filename:pdf"
        },
        "options": {
          "downloadAttachments": true
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "d2kfFLUV2qlW2o43",
          "name": "Gmail account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "7c5278ea-c32f-4f55-9ba4-4448c06c21f0",
      "name": "JavaScriptコード",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        16
      ],
      "parameters": {
        "jsCode": "// Get email data\nconst email = $input.item.json;\nconst binary = $input.item.binary;\n\n// Check if we have binary attachments\nif (!binary || Object.keys(binary).length === 0) {\n  return { \n    json: { \n      error: 'No invoice attachment found',\n      emailId: email.id,\n      emailSubject: email.subject\n    } \n  };\n}\n\n// Find first PDF or image attachment\nlet invoiceFile = null;\nlet invoiceKey = null;\n\nfor (const key in binary) {\n  const file = binary[key];\n  if (file.mimeType?.includes('pdf') || \n      file.mimeType?.includes('image') ||\n      file.mimeType?.includes('png') ||\n      file.mimeType?.includes('jpg')) {\n    invoiceFile = file;\n    invoiceKey = key;\n    break;\n  }\n}\n\nif (!invoiceFile) {\n  return { \n    json: { \n      error: 'No PDF or image attachment found',\n      emailId: email.id,\n      emailSubject: email.subject\n    } \n  };\n}\n\n// The binary data in n8n is already base64 encoded\n// Just use it directly without re-encoding\nlet base64Data = invoiceFile.data;\n\n// If it's a Buffer, convert to base64 string\nif (Buffer.isBuffer(base64Data)) {\n  base64Data = base64Data.toString('base64');\n}\n\n// Build the data URL for OCR.space\nconst dataUrl = `data:${invoiceFile.mimeType};base64,${base64Data}`;\n\nreturn {\n  json: {\n    emailId: email.id,\n    emailSubject: email.subject,\n    emailFrom: email.from,\n    emailDate: email.date,\n    attachmentData: base64Data,\n    attachmentName: invoiceFile.fileName,\n    mimeType: invoiceFile.mimeType,\n    dataUrl: dataUrl\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "4ddb1479-1b7f-4f8d-ad41-1a92654c98c8",
      "name": "シートへの行追加・更新",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1296,
        -48
      ],
      "parameters": {
        "columns": {
          "value": {
            "Amount": "={{ $json.amount }}",
            "Status": "Pending",
            "Vendor": "={{ $json.vendor }}",
            "Currency": "={{ $json.currency }}",
            "Due Date": "={{ $json.dueDate }}",
            "Email ID": "={{ $node[\"Code in JavaScript\"].json.emailId }}",
            "Timestamp": "={{ $now.format('yyyy-MM-dd HH:mm:ss') }}",
            "Description": "={{ $json.description }}",
            "Invoice Date": "={{ $json.invoiceDate }}",
            "Invoice Number": "={{ $json.invoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed By",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Processed By",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Invoice Number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TWE856dG0g0bSRr3M4SKPcpnJ32veWlq3m_DWJoSaTQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=\"YOUR_SPREADSHEET_ID\""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "hVo2bSobLUbf5b3a",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "abea5730-c60f-47f4-83b3-50cb42c6c9e0",
      "name": "Slack承認リクエスト",
      "type": "n8n-nodes-base.slack",
      "position": [
        1904,
        -48
      ],
      "webhookId": "4f4fa1f8-f072-4ceb-b802-68904622847d",
      "parameters": {
        "select": "channel",
        "message": "=🧾 *New Invoice Requires Approval*\n\n*Vendor:* {{ $json.vendor }}\n*Amount:* ${{ $json.amount }} {{ $json.currency }}\n*Invoice #:* {{ $json.invoiceNumber }}\n*Due Date:* {{ $json.dueDate }}\n*Description:* {{ $json.description }}",
        "options": {},
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "operation": "sendAndWait",
        "authentication": "oAuth2",
        "approvalOptions": {
          "values": {
            "approvalType": "double"
          }
        }
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "955f6439-8d79-4f9f-b35c-7bf3e39f6aad",
      "name": "Slack却下メッセージ",
      "type": "n8n-nodes-base.slack",
      "position": [
        1296,
        144
      ],
      "webhookId": "e4b6a100-ab6c-4908-8909-a37c5c210aad",
      "parameters": {
        "text": "=Channel: #invoice-approvals\n\nText:\n❌ *Invoice Auto-Rejected*\n\nAn invoice was rejected by AI analysis:\n\n- From: {{ $node[\"Code in JavaScript\"].json.emailFrom }}\n- Subject: {{ $node[\"Code in JavaScript\"].json.emailSubject }}\n- Reason: Did not pass qualification checks\n- Confidence: {{ $json.confidence }}%\n- Red Flags: {{ $json.redFlags.join(', ') }}\n\nThe email has been labeled \"Rejected\" in Gmail.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "424382f8-ff99-457e-9714-569c83e29157",
      "name": "資格確認",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1237bc0c-6f1a-4a3b-98ff-45369c8ebc06",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.qualified }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "be9d4c45-2bb3-4ca4-944e-65045fa75a60",
      "name": "インボイスデータ解析",
      "type": "n8n-nodes-base.code",
      "position": [
        720,
        0
      ],
      "parameters": {
        "jsCode": "// Get OCR result\nconst ocrResult = $json;\n\n// Extract the text\nlet extractedText = '';\n\nif (ocrResult.ParsedResults && ocrResult.ParsedResults[0]) {\n  extractedText = ocrResult.ParsedResults[0].ParsedText;\n} else {\n  return {\n    json: {\n      error: 'OCR failed to extract text',\n      qualified: false,\n      redFlags: ['Could not read invoice text']\n    }\n  };\n}\n\n// Helper function to parse dates correctly without timezone issues\nfunction parseDate(dateString) {\n  // Try to parse dates like \"October 1, 2025\"\n  const date = new Date(dateString + ' 12:00:00 UTC'); // Add noon UTC to avoid timezone shifts\n  \n  if (!isNaN(date)) {\n    const year = date.getUTCFullYear();\n    const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n    const day = String(date.getUTCDate()).padStart(2, '0');\n    return `${year}-${month}-${day}`;\n  }\n  \n  return '';\n}\n\n// Parse invoice fields using regex\nconst invoiceData = {\n  qualified: true,\n  vendor: '',\n  invoiceNumber: '',\n  amount: 0,\n  currency: 'USD',\n  invoiceDate: '',\n  dueDate: '',\n  description: '',\n  confidence: 100,\n  redFlags: []\n};\n\n// Extract Vendor (line after \"From:\")\nconst vendorMatch = extractedText.match(/From:\\s*([^\\n]+)/i);\nif (vendorMatch) {\n  invoiceData.vendor = vendorMatch[1].trim();\n}\n\n// Extract Invoice Number\nconst invoiceNumMatch = extractedText.match(/Invoice Number:\\s*([^\\n]+)/i);\nif (invoiceNumMatch) {\n  invoiceData.invoiceNumber = invoiceNumMatch[1].trim();\n}\n\n// Extract Amount (from \"Total:\" line) - CRITICAL!\nconst totalMatch = extractedText.match(/Total:\\s*\\$\\s*([0-9,]+\\.?[0-9]*)/i);\nif (totalMatch) {\n  invoiceData.amount = parseFloat(totalMatch[1].replace(/,/g, ''));\n}\n\n// If Total not found, try Amount line\nif (invoiceData.amount === 0) {\n  const amountMatch = extractedText.match(/Amount:\\s*\\$\\s*([0-9,]+\\.?[0-9]*)/i);\n  if (amountMatch) {\n    invoiceData.amount = parseFloat(amountMatch[1].replace(/,/g, ''));\n  }\n}\n\n// Extract Currency\nconst currencyMatch = extractedText.match(/(USD|EUR|GBP|CAD)/i);\nif (currencyMatch) {\n  invoiceData.currency = currencyMatch[1].toUpperCase();\n}\n\n// Extract Invoice Date - FIXED!\nconst dateMatch = extractedText.match(/Date:\\s*([^\\n]+)/i);\nif (dateMatch) {\n  const dateStr = dateMatch[1].trim();\n  invoiceData.invoiceDate = parseDate(dateStr);\n}\n\n// Extract Due Date - FIXED!\nconst dueMatch = extractedText.match(/Due Date:\\s*([^\\n]+)/i);\nif (dueMatch) {\n  const dateStr = dueMatch[1].trim();\n  invoiceData.dueDate = parseDate(dateStr);\n}\n\n// Extract Description\nconst descMatch = extractedText.match(/Description:\\s*([^\\n]+)/i);\nif (descMatch) {\n  invoiceData.description = descMatch[1].trim();\n}\n\n// Validation checks\nif (!invoiceData.vendor) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Missing vendor name');\n}\n\nif (!invoiceData.invoiceNumber) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Missing invoice number');\n}\n\nif (invoiceData.amount === 0) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Missing or invalid amount');\n}\n\nif (invoiceData.amount > 10000) {\n  invoiceData.qualified = false;\n  invoiceData.redFlags.push('Amount exceeds $10,000');\n}\n\nreturn {\n  json: invoiceData\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "36afc95e-af94-4c98-a458-744e9bfd1139",
      "name": "Slack用フォーマット",
      "type": "n8n-nodes-base.code",
      "position": [
        1504,
        -48
      ],
      "parameters": {
        "jsCode": "const sheetData = $node[\"Append or update row in sheet\"].json;\n\nreturn {\n  json: {\n    vendor: sheetData.Vendor,\n    amount: sheetData.Amount,\n    currency: sheetData.Currency,\n    invoiceNumber: sheetData[\"Invoice Number\"],\n    invoiceDate: sheetData[\"Invoice Date\"],  // ← ADD THIS LINE!\n    dueDate: sheetData[\"Due Date\"],\n    description: sheetData.Description\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "b524a093-e827-4049-b0c9-809dc839465e",
      "name": "却下メッセージ",
      "type": "n8n-nodes-base.slack",
      "position": [
        2896,
        16
      ],
      "webhookId": "019dcb52-375d-4fff-9e0d-d4d5b4ac0282",
      "parameters": {
        "text": "❌ Invoice rejected",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "afcf2f08-41ec-4ce5-bb32-98733317379f",
      "name": "成功メッセージ",
      "type": "n8n-nodes-base.slack",
      "position": [
        3248,
        -176
      ],
      "webhookId": "ae7fc4b9-99a3-41ad-ba4e-4e4a15a52303",
      "parameters": {
        "text": "✅ Invoice posted to Xero",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09LDKZJGBB",
          "cachedResultName": "invoice-approvals"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "plTTzKNjrWG2CYjh",
          "name": "Slack account"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2a70f5c0-db5f-44eb-8eb8-24c978892049",
      "name": "却下ステータス更新",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2704,
        16
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "Rejected",
            "Invoice Number": "={{ $('Clean Invoice Payload').item.json.invoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed By",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Processed By",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Invoice Number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TWE856dG0g0bSRr3M4SKPcpnJ32veWlq3m_DWJoSaTQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=\"YOUR_SPREADSHEET_ID\""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "hVo2bSobLUbf5b3a",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "f775d6e5-a97b-4aea-be73-f6a3030cbfc3",
      "name": "承認ステータス更新",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3024,
        -176
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "Approved",
            "Invoice Number": "={{ $('Clean Invoice Payload').item.json.invoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Processed By",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Processed By",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Invoice Number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "=Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=\"YOUR_SPREADSHEET_ID\""
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "hVo2bSobLUbf5b3a",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b062f234-61a1-4913-8135-be9d9be322a8",
      "name": "処理済みラベル追加",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2832,
        -176
      ],
      "webhookId": "a5cbed4c-0c43-4bf0-8114-e8fbbf987e9e",
      "parameters": {
        "labelIds": [
          "Label_3710233975993850496"
        ],
        "messageId": "={{$node[\"Code in JavaScript\"].json.emailId}}",
        "operation": "addLabels"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "d2kfFLUV2qlW2o43",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "854afcd4-6559-4753-b75d-2a65766c492d",
      "name": "却下ラベル追加",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2432,
        16
      ],
      "webhookId": "2e5f020d-ed42-438c-8744-4fdd602145c7",
      "parameters": {
        "labelIds": [
          "Label_8899302689673155790"
        ],
        "messageId": "={{$node[\"Code in JavaScript\"].json.emailId}}",
        "operation": "addLabels"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "d2kfFLUV2qlW2o43",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "025efb16-32dd-4a7e-8349-baef18b32040",
      "name": "複数連絡先取得",
      "type": "n8n-nodes-base.xero",
      "position": [
        2416,
        -176
      ],
      "parameters": {
        "limit": 1,
        "options": {},
        "resource": "contact",
        "operation": "getAll",
        "organizationId": "=9a46b4a9-feac-446e-a04d-4e7421565898"
      },
      "credentials": {
        "xeroOAuth2Api": {
          "id": "XfSNoqDEDyivPRYX",
          "name": "Xero account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b43a1017-8ecb-4c39-b92f-8865349ccec2",
      "name": "インボイスペイロード整理",
      "type": "n8n-nodes-base.code",
      "position": [
        1696,
        -48
      ],
      "parameters": {
        "jsCode": "const invoiceData = { ...$node[\"Format for Slack\"].json };\n\n// Strip off any vendor or itemCode field that might be passed\ndelete invoiceData.vendor;\ndelete invoiceData.itemCode;\ndelete invoiceData[\"Item Code Name or ID\"]; // Just in case\n\nreturn [{ json: invoiceData }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a77a3860-e69a-428f-b74e-d926859c83e3",
      "name": "インボイス作成",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2624,
        -176
      ],
      "parameters": {
        "url": "https://api.xero.com/api.xro/2.0/Invoices",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"Type\": \"ACCPAY\",\n  \"Contact\": {\n    \"ContactID\": \"{{$node[\"Get many contacts\"].json.ContactID}}\"\n  },\n  \"Date\": \"{{$node[\"Format for Slack\"].json.invoiceDate}}\",\n  \"DueDate\": \"{{$node[\"Format for Slack\"].json.dueDate}}\",\n  \"InvoiceNumber\": \"{{$node[\"Format for Slack\"].json.invoiceNumber}}\",\n  \"Reference\": \"{{$node[\"Format for Slack\"].json.invoiceNumber}}\",\n  \"Status\": \"DRAFT\",\n  \"LineAmountTypes\": \"Exclusive\",\n  \"LineItems\": [\n    {\n      \"Description\": \"{{$node[\"Format for Slack\"].json.description}}\",\n      \"Quantity\": 1,\n      \"UnitAmount\": {{$node[\"Format for Slack\"].json.amount}},\n      \"AccountCode\": \"463\",\n      \"TaxType\": \"INPUT2\"\n    }\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "xero-tenant-id",
              "value": "=\"{{$credentials.xero.apiKey}}\""
            }
          ]
        },
        "nodeCredentialType": "xeroOAuth2Api"
      },
      "credentials": {
        "xeroOAuth2Api": {
          "id": "XfSNoqDEDyivPRYX",
          "name": "Xero account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "270ea877-b081-4704-8137-3cbcf62606fb",
      "name": "有効な添付ファイル?",
      "type": "n8n-nodes-base.if",
      "position": [
        288,
        16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5b78e677-d068-411a-8c43-e41a9725f370",
              "operator": {
                "type": "number",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{$json.error}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4128986d-09d7-44b5-a9f5-5f8a532c1712",
      "name": "承認済み?",
      "type": "n8n-nodes-base.if",
      "position": [
        2128,
        -48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b58f3729-809c-4b21-9210-6c581dbeed50",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8400ed04-51ba-4cc6-92cc-abb03a09e258",
      "name": "テキスト抽出",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        544,
        0
      ],
      "parameters": {
        "url": "https://api.ocr.space/parse/image",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"name\": \"apikey\",\n  \"value\": \"{{$credentials.ocrspaceApi.apiKey}}\"\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "d132fdec-f017-49f6-a4bc-8a938df37d98",
      "name": "付箋",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -912,
        -464
      ],
      "parameters": {
        "width": 608,
        "height": 1696,
        "content": "### Automate Invoice Processing with Gmail, OCR.space, Slack & Xero\n\nThis n8n template demonstrates how to automatically extract, validate, approve, and sync invoices received via email using AI and automation — reducing manual processing time and minimizing errors.\n\n### Use Cases\n\n- Finance teams looking to eliminate invoice approval bottlenecks  \n- Businesses that receive PDF/image invoices via email  \n- Companies currently logging invoices manually into spreadsheets or accounting tools  \n\n### How It Works\n\n1. **Trigger**: Watches for new emails in Gmail with PDF/image attachments.  \n2. **OCR**: Sends the attachment to OCR.space API (https://ocr.space/OCRAPI) to extract invoice text.  \n3. **Parsing**: Extracts key fields:  \n   - Vendor  \n   - Invoice number  \n   - Amount  \n   - Currency  \n   - Invoice date  \n   - Due date  \n   - Description  \n4. **Validation Logic**:  \n   - Checks if amount is valid  \n   - Ensures vendor and invoice number are present  \n   - Flags high-value invoices (e.g., over $10,000)  \n5. **Routing**:  \n   - If invalid: \n   - Sends a Slack message highlighting issues\n   - Labels email as **Rejected**  \n   - If valid:  \n     - Logs the invoice into Google Sheets  \n     - Sends a Slack message to the finance team for approval  \n     - After approval, creates a draft invoice in Xero  \n     - Labels the email as **Processed** in Gmail  \n\n### Customisation Options\n\n- Swap Gmail trigger with a file uploader or webhook  \n- Adjust the Slack notification channels or approval thresholds  \n- Replace Xero with QuickBooks, Zoho, or another tool  \n- Adapt log storage from Google Sheets to Airtable or Notion  \n- Add a reminder flow if no approval is received within 24h  \n\n### Prerequisites/Credential Setup\n\nTo use this workflow securely, you'll need the following credentials set up in n8n:\n\n- **Gmail OAuth2** – to watch for incoming invoice emails and apply labels\n- **OCR.space API** – create an HTTP Credential in n8n named `ocrspaceApi`, with your OCR.space key\n- **Slack OAuth2 or Webhook (with connected bot)** – to send approval/rejection messages to your team\n- **Google Sheets OAuth2 credentials** – to log processed invoices for audit and tracking\n- **Xero OAuth2 credentials (via n8n’s native integration)** – connect your Xero account to push approved invoices in Draft status\n \n### Secure Configuration\n- All credential fields use **n8n Credential Types**  \n- No sensitive data (API keys, spreadsheet IDs) is hardcoded  \n\n### Why This Helps\n\n- Reduces time spent manually reviewing and copying invoices\n- Maintains structured logs with clean data\n- Automates Slack approvals and reduces email back-and-forth\n- Improves audit trails and AP visibility across tools\n\n---\nWith this template, finance teams can streamline invoice approvals, reduce processing time, and maintain a clean audit trail, all fully automated."
      },
      "typeVersion": 1
    },
    {
      "id": "b16d6e58-0125-4735-b939-040945fcc89b",
      "name": "付箋1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        -336
      ],
      "parameters": {
        "width": 1248,
        "height": 640,
        "content": "## 2. Approve or Reject Invoice in Slack\n[Read more about Slack Approval workflows in n8n](https://docs.n8n.io/integrations/slack/)\n\nAfter parsing, the workflow evaluates whether the invoice meets preset criteria (e.g., approved vendors or amount limits). It logs the result in a Google Sheet and sends a Slack message for manual approval. Based on the response, it either proceeds to Xero or marks it as rejected.\n\nSetup Tip: Replace YOUR_SLACK_CLIENT_ID with the Client ID from your Slack apps page - https://api.slack.com/apps.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "af22b982-18c5-4adc-9e88-d7ecf53f357c",
      "name": "付箋2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        -336
      ],
      "parameters": {
        "width": 1120,
        "height": 640,
        "content": "## 1. Extract & Parse Invoice from Gmail\n[Read more about the Gmail and HTTP Request nodes](https://docs.n8n.io/integrations/builtin/email-read-imap/)\n  \nThis section listens for new emails via Gmail, checks if an attachment exists and is valid, then extracts and parses invoice data using OCR (via OCR.Space API). The data is cleaned and prepared for downstream steps.\n\nSetup Tip: Replace YOUR_GOOGLE_CLIENT_ID with the Client ID from your Google Console - https://console.cloud.google.com/ for your Google Sheets, Google Docs, Gmail."
      },
      "typeVersion": 1
    },
    {
      "id": "422c5b66-d77a-4224-b689-e4b57152373e",
      "name": "付箋3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2288,
        -336
      ],
      "parameters": {
        "width": 1168,
        "height": 640,
        "content": "## 3. Sync Outcome to Xero & Notify\n[Read more about Xero and Gmail automation](https://docs.n8n.io/integrations/xero/)\n\nIf the invoice is approved, the workflow fetches the contact from Xero, creates the invoice, updates Gmail labels, logs final status in Google Sheets, and sends a success message in Slack. If rejected, it applies a different Gmail label, updates status, and notifies the team.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "a1d9da45-06e7-460c-9c56-bc430ee568b6",
  "connections": {
    "8400ed04-51ba-4cc6-92cc-abb03a09e258": {
      "main": [
        [
          {
            "node": "be9d4c45-2bb3-4ca4-944e-65045fa75a60",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "189e9199-b377-4acc-a0e7-d5769e69a762": {
      "main": [
        [
          {
            "node": "7c5278ea-c32f-4f55-9ba4-4448c06c21f0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4128986d-09d7-44b5-a9f5-5f8a532c1712": {
      "main": [
        [
          {
            "node": "025efb16-32dd-4a7e-8349-baef18b32040",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "854afcd4-6559-4753-b75d-2a65766c492d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a77a3860-e69a-428f-b74e-d926859c83e3": {
      "main": [
        [
          {
            "node": "b062f234-61a1-4913-8135-be9d9be322a8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "36afc95e-af94-4c98-a458-744e9bfd1139": {
      "main": [
        [
          {
            "node": "b43a1017-8ecb-4c39-b92f-8865349ccec2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "025efb16-32dd-4a7e-8349-baef18b32040": {
      "main": [
        [
          {
            "node": "a77a3860-e69a-428f-b74e-d926859c83e3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "854afcd4-6559-4753-b75d-2a65766c492d": {
      "main": [
        [
          {
            "node": "2a70f5c0-db5f-44eb-8eb8-24c978892049",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7c5278ea-c32f-4f55-9ba4-4448c06c21f0": {
      "main": [
        [
          {
            "node": "270ea877-b081-4704-8137-3cbcf62606fb",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "be9d4c45-2bb3-4ca4-944e-65045fa75a60": {
      "main": [
        [
          {
            "node": "424382f8-ff99-457e-9714-569c83e29157",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b062f234-61a1-4913-8135-be9d9be322a8": {
      "main": [
        [
          {
            "node": "f775d6e5-a97b-4aea-be73-f6a3030cbfc3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "424382f8-ff99-457e-9714-569c83e29157": {
      "main": [
        [
          {
            "node": "4ddb1479-1b7f-4f8d-ad41-1a92654c98c8",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "955f6439-8d79-4f9f-b35c-7bf3e39f6aad",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b43a1017-8ecb-4c39-b92f-8865349ccec2": {
      "main": [
        [
          {
            "node": "abea5730-c60f-47f4-83b3-50cb42c6c9e0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "270ea877-b081-4704-8137-3cbcf62606fb": {
      "main": [
        [
          {
            "node": "8400ed04-51ba-4cc6-92cc-abb03a09e258",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "abea5730-c60f-47f4-83b3-50cb42c6c9e0": {
      "main": [
        [
          {
            "node": "4128986d-09d7-44b5-a9f5-5f8a532c1712",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f775d6e5-a97b-4aea-be73-f6a3030cbfc3": {
      "main": [
        [
          {
            "node": "afcf2f08-41ec-4ce5-bb32-98733317379f",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2a70f5c0-db5f-44eb-8eb8-24c978892049": {
      "main": [
        [
          {
            "node": "b524a093-e827-4049-b0c9-809dc839465e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4ddb1479-1b7f-4f8d-ad41-1a92654c98c8": {
      "main": [
        [
          {
            "node": "36afc95e-af94-4c98-a458-744e9bfd1139",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

上級 - 請求書処理, AI要約

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
上級
ノード数24
カテゴリー2
ノードタイプ9
難易度説明

上級者向け、16ノード以上の複雑なワークフロー

作成者
Abi Odedeyi

Abi Odedeyi

@abiodedeyi

Automation Builder with extensive experience helping businesses streamline processes and generate revenue.

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34