{
  "nodes": [
    {
      "id": "13c00125-be4d-46ed-9efe-72875929e7db",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3152,
        1872
      ],
      "parameters": {
        "width": 400,
        "height": 724,
        "content": "## Classify and forward Gmail invoice attachments to freee with Google Gemini\n\nAutomatically analyze email attachments with AI and forward invoices/receipts to freee's File Box.\n\n## How it works\n\n1. Polls Gmail for new emails with attachments every minute\n2. Extracts text from PDF attachments and sends it to Google Gemini for classification\n3. If Gemini identifies the document as an invoice or receipt, re-fetches the attachment and forwards it to freee's File Box email address\n\n## Setup steps\n\n1. **Get freee receiving email**: freee Accounting \u2192 File Box \u2192 Settings\n2. **Set environment variable**: Set `FREEE_FORWARDING_EMAIL` to freee's receiving address\n3. **Configure Credentials**:\n   - Gmail OAuth2 (read + send permissions)\n   - Google Gemini API\n4. **Activate the workflow**"
      },
      "typeVersion": 1
    },
    {
      "id": "10ea6b19-c70d-4d34-bc45-d04c7fb92faf",
      "name": "Filter Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2608,
        2032
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 292,
        "content": "### Receive & Filter\nPolls Gmail every minute and filters out emails without attachments using the Content-Type header."
      },
      "typeVersion": 1
    },
    {
      "id": "7b93689a-ee1f-484e-ac10-bc23da8eb465",
      "name": "AI Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2064,
        1920
      ],
      "parameters": {
        "color": 7,
        "width": 600,
        "height": 328,
        "content": "### AI Classification\nExtracts text from the PDF attachment, then sends it along with the email body to Google Gemini to classify the document as invoice, receipt, or other."
      },
      "typeVersion": 1
    },
    {
      "id": "c920d6b4-f715-4137-b83c-0a2720a614d6",
      "name": "Forward Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1264,
        1824
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 300,
        "content": "### Forward to freee\nRe-fetches the original attachment and forwards the email to freee's File Box receiving address."
      },
      "typeVersion": 1
    },
    {
      "id": "4f994f2b-b6d3-4b35-b25e-2b473f9fb52d",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -2560,
        2160
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "includeSpamTrash": false
        },
        "options": {
          "downloadAttachments": true
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "87c2e3a2-51e5-4858-a5c2-34990b652b81",
      "name": "Has Attachment",
      "type": "n8n-nodes-base.if",
      "position": [
        -2336,
        2160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-has-attachment",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.headers?.['content-type'] }}",
              "rightValue": "multipart/mixed"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2fa81cca-5513-4d6a-a2e0-ce8e8b2dbcf9",
      "name": "No Attachment - End",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -2016,
        2256
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "090ec41a-d07b-4cad-9a3e-4ef779c4a16a",
      "name": "Is Invoice or Receipt",
      "type": "n8n-nodes-base.if",
      "position": [
        -1440,
        2064
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-is-invoice-or-receipt",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ JSON.parse($json.content.parts[0].text).is_invoice_or_receipt }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "85086fde-9fe0-4c63-a49c-9d5e4c627036",
      "name": "Not Target - End",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -1216,
        2160
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9b09d5db-1d7b-4b5a-bde8-38c55eb90004",
      "name": "Forward to freee",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -992,
        1968
      ],
      "parameters": {
        "sendTo": "={{ $env.FREEE_FORWARDING_EMAIL }}",
        "message": "=Auto-forwarded email (AI classification: {{ JSON.parse($('Classify Invoice/Receipt (AI)').item.json.content.parts[0].text).document_type === 'invoice' ? 'Invoice' : 'Receipt' }})\n\n---------- Forwarded message ----------\nFrom: {{ $('Gmail Trigger').item.json.from.text }}\nDate: {{ $('Gmail Trigger').item.json.date }}\nSubject: {{ $('Gmail Trigger').item.json.subject }}\n\n{{ $('Gmail Trigger').item.json.text }}",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {
                "property": "attachment_0"
              }
            ]
          }
        },
        "subject": "=Fwd: {{ $('Gmail Trigger').item.json.subject }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "3fb2f04b-59dc-4dd6-8a03-296d955dc741",
      "name": "Classify Invoice/Receipt (AI)",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        -1792,
        2064
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "role": "model",
              "content": "You are an expert document classifier in a corporate accounting department.\nAccurately determine whether the attached file is an \"invoice\" or \"receipt\".\nDocuments may be in any language.\n\n### Strict Requirements (Most Important)\n\nYou must follow these conditions:\n- Output **only one valid JSON object**\n- Do not include any explanations, notes, conclusions, or reasons before or after the JSON\n- Code blocks (```) are forbidden\n- Not a single character other than JSON is allowed\n- If you cannot follow the above, return:\n  {\"error\":\"invalid_output\"}\n\n### Classification Rules\n\n[Invoice]\n- Keywords: \"Invoice\", \"Bill\", \"Statement\"\n- Invoice amount, total, subtotal\n- Issuer's company name and address\n- Recipient's company name\n- Invoice date, payment due date\n- Line items with quantity and unit price\n\n[Receipt]\n- Keywords: \"Receipt\", \"Acknowledgment\"\n- Amount received\n- Issuer's company name, address, and seal/stamp\n- Phrases like \"Payment received\"\n- Date\n\n[Other (not target)]\n- Quotations, delivery notes, purchase orders, contracts\n- Advertisements, sales emails, newsletters\n- Internal notices, meeting materials\n\n### Output Format (Strict)\n\nOutput JSON with **only** these keys.\nAdding or removing keys is forbidden.\n\n{\n  \"is_invoice_or_receipt\": boolean,\n  \"document_type\": \"invoice\" | \"receipt\" | \"other\",\n  \"confidence\": number,\n  \"reason\": string\n}\n\n### Constraints for reason\n- Single sentence only\n- 80 characters or less\n- No line breaks\n- Do not write reasons outside the JSON\n"
            },
            {
              "content": "=Please classify the following email and attachment.\n\n[Email Subject]\n{{ $('Gmail Trigger').item.json.headers.subject }}\n\n[Email From]\n{{ $('Gmail Trigger').item.json.headers.from }}\n\n[Email Body]\n{{ $('Gmail Trigger').item.json.text }}\n\n[Attachment Content]\n{{ $json.text }}"
            }
          ]
        },
        "builtInTools": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "7c571379-c41f-47c8-ab12-c89e5035cbbf",
      "name": "Extract Text from PDF",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -2016,
        2064
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "attachment_0"
      },
      "typeVersion": 1.1
    },
    {
      "id": "922d2b80-2e98-4ace-991f-a191a4ee71a8",
      "name": "Get Attachment",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1216,
        1968
      ],
      "parameters": {
        "simple": false,
        "options": {
          "downloadAttachments": true
        },
        "messageId": "={{ $('Gmail Trigger').item.json.id }}",
        "operation": "get"
      },
      "typeVersion": 2.1
    }
  ],
  "connections": {
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Has Attachment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Attachment": {
      "main": [
        [
          {
            "node": "Forward to freee",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Attachment": {
      "main": [
        [
          {
            "node": "Extract Text from PDF",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Attachment - End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Text from PDF": {
      "main": [
        [
          {
            "node": "Classify Invoice/Receipt (AI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Invoice or Receipt": {
      "main": [
        [
          {
            "node": "Get Attachment",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Not Target - End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Invoice/Receipt (AI)": {
      "main": [
        [
          {
            "node": "Is Invoice or Receipt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}