{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Invoice Duplicate Checker v2",
  "tags": [],
  "nodes": [
    {
      "id": "4477bb85-84c0-41a0-a05c-6b3bac0698f3",
      "name": "Check Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -528,
        112
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Master Finance File"
        }
      },
      "typeVersion": 4,
      "alwaysOutputData": true
    },
    {
      "id": "51fa97a3-3b7f-42ea-9ead-4a5a9e239803",
      "name": "Already Exists?",
      "type": "n8n-nodes-base.if",
      "position": [
        -208,
        112
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.duplicate }}",
              "value2": "true"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7553896e-f939-4262-af1f-756b25c5be25",
      "name": "Add to Master List",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        64,
        256
      ],
      "parameters": {
        "columns": {
          "value": {
            "Invoice Number": "={{ $('HTTP Request').first().json.data.invoice_number }}",
            "Final Amount (EUR)": "={{ $('HTTP Request').first().json.data.total_amount }}"
          },
          "schema": [
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Original Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Original Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Exchange Rate",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Exchange Rate",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Final Amount (EUR)",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Final Amount (EUR)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Master Finance File"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "2fd986c1-a8b6-4adc-aec6-7daf8685295c",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -1328,
        112
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "labelIds": []
        },
        "options": {
          "downloadAttachments": true
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "e5527bfa-9a24-4208-b1e3-ca695830d977",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -1088,
        112
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery",
        "binaryPropertyName": "=attachment_0"
      },
      "typeVersion": 1.1
    },
    {
      "id": "61cb08f9-ad41-4d68-b46d-3e44218464a2",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        -928,
        112
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "61f1027c-dc46-49a0-8450-ed63cd67e8c9",
              "name": "data",
              "type": "string",
              "value": "=data:application/pdf;base64,{{ $json.data }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2b847aff-69f7-4240-b1b2-5af669594158",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -768,
        112
      ],
      "parameters": {
        "url": "https://extractor.easybits.tech/api/pipelines/YOUR_PIPELINE_ID",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"files\": [\n    \"{{ $json.data }}\"\n  ]\n} ",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpBearerAuth"
      },
      "typeVersion": 4.3
    },
    {
      "id": "f6d5d00e-1e16-4fe7-bfb5-a5313c1b9d86",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        -368,
        112
      ],
      "parameters": {
        "jsCode": "const invoiceNumber = $('HTTP Request').first().json.data.invoice_number;\nconst rows = $input.all();\n\n// Debug: log what we're working with\nconst allInvoiceNumbers = rows.map(row => row.json[\"Invoice Number\"]).filter(Boolean);\n\nconst match = rows.filter(row => {\n  const cellValue = row.json[\"Invoice Number\"];\n  if (!cellValue) return false;\n  return String(cellValue).trim() === String(invoiceNumber).trim();\n});\n\nreturn [{\n  json: {\n    duplicate: match.length > 0 ? \"true\" : \"false\",\n    invoice_number: invoiceNumber,\n    found_in_sheet: allInvoiceNumbers,\n    rows_checked: rows.length\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "1b20a65c-608c-4118-a914-5141edab83ac",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1392,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 224,
        "height": 336,
        "content": "## \ud83d\udce7 Email Intake\nPolls Gmail every minute for emails with the **invoice** label.\nDownloads attachments automatically."
      },
      "typeVersion": 1
    },
    {
      "id": "bf9d9a2f-5a9c-404b-b926-2e508a183224",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 336,
        "content": "## \ud83d\udcc4 Invoice Extraction with easybits\nExtracts the PDF attachment, converts it to base64, and sends it to the **easybits' extractor API** to pull structured invoice data (invoice number, amount, etc.)."
      },
      "typeVersion": 1
    },
    {
      "id": "22ca9538-3bad-4cda-a10a-ae8ec96f79d8",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -592,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 336,
        "content": "## \ud83d\udd0d Duplicate Check\nReads all rows from the **Master Finance File** in Google Sheets. A Code node compares the extracted invoice number against existing entries. Returns `duplicate: true/false`."
      },
      "typeVersion": 1
    },
    {
      "id": "3d6bc7f4-f812-49a4-a23e-0a63f8b39e29",
      "name": "Slack: Alert Finance",
      "type": "n8n-nodes-base.slack",
      "position": [
        64,
        -64
      ],
      "parameters": {
        "text": "=\ud83d\udea8 *Duplicate Invoice Detected*  Invoice number {{ $('HTTP Request').first().json.data.invoice_number }} was already submitted. Please review before processing.",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        },
        "select": "user",
        "otherOptions": {}
      },
      "typeVersion": 2
    },
    {
      "id": "e4f0a16b-8041-4202-989b-63a647a64728",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        -208
      ],
      "parameters": {
        "color": 7,
        "width": 304,
        "height": 304,
        "content": "## \ud83d\udea8 Duplicate Found\nIf the invoice **already exists** in the sheet, a Slack DM is sent to the user with the duplicate invoice number for manual review."
      },
      "typeVersion": 1
    },
    {
      "id": "1b22bf73-e06f-40af-95d8-09564226374b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 304,
        "height": 304,
        "content": "## \u2705 New Invoice\nIf the invoice is **not** a duplicate, it gets appended to the Master Finance File in Google Sheets with the invoice number and total amount."
      },
      "typeVersion": 1
    },
    {
      "id": "4d296449-cb5c-466e-b618-a39fe24ee6f0",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2192,
        -304
      ],
      "parameters": {
        "width": 784,
        "height": 832,
        "content": "# \ud83d\udd0d Invoice Duplicate Checker\n\n## How It Works\nThis workflow automatically detects duplicate invoices from Gmail. Incoming PDF attachments are scanned by the easybits data extraction solution, then checked against the Master Finance File in Google Sheets. Duplicates trigger a Slack alert \u2013 new invoices get added to the sheet.\n\n**Flow overview:**\n1. Gmail picks up new emails labeled as invoices (polls every minute)\n2. The PDF attachment is extracted and converted to base64\n3. easybits Extractor reads the document and returns structured data\n4. The invoice number is compared against all existing entries in Google Sheets\n5. If duplicate \u2192 Slack DM alert to user\n6. If new \u2192 Invoice is appended to the Master Finance File\n\n---\n\n## Setup Guide\n\n**1. easybits Extractor** \u2013 Create a pipeline at extractor.easybits.tech with fields: `invoice_number` (String) and `total_amount` (Number). Copy your Pipeline ID and API Key.\n\n**2. HTTP Request node** \u2013 Replace the Pipeline ID in the URL. Add a Bearer Auth credential with your API Key.\n\n**3. Gmail Trigger** \u2013 Connect via OAuth2. Create an \"invoice\" label in Gmail and set it as the filter. Enable Download Attachments.\n\n**4. Google Sheets** \u2013 Connect both sheet nodes via OAuth2. Select your spreadsheet. Required columns: **Invoice Number** and **Final Amount (EUR)**.\n\n**5. Slack** \u2013 Create a Slack App at api.slack.com/apps. Add scopes: `chat:write`, `chat:write.public`, `channels:read`, `groups:read`, `users:read`, `users.profile:read`. Install via Settings \u2192 Install App. Add the Bot Token as a Slack API credential in n8n.\n\n**6. Activate** \u2013 Toggle the workflow on, label an invoice email, and test. Send the same invoice twice to verify the duplicate alert."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "connections": {
    "Edit Fields": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Check Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Already Exists?": {
      "main": [
        [
          {
            "node": "Slack: Alert Finance",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Add to Master List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Already Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Google Sheets": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}