{
  "id": "UGSS5zt4TXxF32mr",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "GPT-4.1-mini Powered Invoice Processing from Gmail to Google Sheets with Slack Approval",
  "tags": [],
  "nodes": [
    {
      "id": "6a927310-5fc7-43bd-87af-424bd7c55cb0",
      "name": "1. New Invoice Email Received",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -848,
        -528
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "invoice",
          "includeDrafts": false,
          "includeSpamTrash": false
        },
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "f8ccf24e-2bd0-45d7-8913-390017b8bb86",
      "name": "2. Get Email Attachments",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -624,
        -528
      ],
      "parameters": {
        "simple": false,
        "options": {
          "downloadAttachments": true
        },
        "messageId": "={{$json.id}}",
        "operation": "get"
      },
      "typeVersion": 2.1
    },
    {
      "id": "9735648c-b000-4609-ba2a-f3abf3f9ecf4",
      "name": "3. Extract Text from PDF",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -400,
        -528
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "attachment_0"
      },
      "typeVersion": 1
    },
    {
      "id": "35f7be1c-4edf-439a-8fcb-0bca17c9572f",
      "name": "4. Prepare Text for AI",
      "type": "n8n-nodes-base.set",
      "position": [
        -176,
        -528
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "80247922-4a11-451d-9aa6-605b7ca9042b",
              "name": "clean_text",
              "type": "string",
              "value": "={{$json.text || $json.rawText || ''}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d2e5f759-f7f1-4f1e-bdce-9953e010067a",
      "name": "5. Extract Invoice Data with AI",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        48,
        -528
      ],
      "parameters": {
        "text": "=You are a professional accounting data processor.\nExtract the specified items from the text below and output them in JSON format.\n\n# Instructions\n- Strictly adhere to the specified JSON object format.\n- You must only output the JSON object.\n- Do not include any explanatory text or code blocks like ```json before or after the JSON.\n- For any items not found in the text, use an empty string \"\" or 0.\n\n# Output Format\n{\n  \"invoice_number\": \"\",\n  \"issue_date\": \"\",\n  \"bill_to_name\": \"\",\n  \"total_amount\": 0,\n  \"due_date\": \"\"\n}\n\n# Target Text\n{{ $json.clean_text }}",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "1997c1a1-6d0b-4978-b016-e165bff3b9fe",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        64,
        -304
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "a0873ce5-7bc6-432c-9782-7f0f38cbbe36",
      "name": "Webhook (Approve)",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -864,
        -16
      ],
      "parameters": {
        "path": "approve",
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "3c059939-48aa-4f1e-9885-ba4090a53c07",
      "name": "Webhook (Reject)",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -864,
        208
      ],
      "parameters": {
        "path": "reject",
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "084e5e25-96e7-481a-8bfc-41ebb99d1ca1",
      "name": "10a. Send Approval Confirmation",
      "type": "n8n-nodes-base.slack",
      "position": [
        -192,
        -16
      ],
      "parameters": {
        "text": "=This invoice has been approved. ID: {{$json.invoice_id}}",
        "select": "channel",
        "channelId": "YOUR_SLACK_CHANNEL_ID",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.3
    },
    {
      "id": "3168c089-d89a-4649-b0d6-498417207953",
      "name": "10b. Send Rejection Confirmation",
      "type": "n8n-nodes-base.slack",
      "position": [
        -192,
        208
      ],
      "parameters": {
        "text": "=This invoice has been rejected. ID: {{$json.invoice_id}}",
        "select": "channel",
        "channelId": "YOUR_SLACK_CHANNEL_ID",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.3
    },
    {
      "id": "61afe930-9395-4ca5-aebd-c610edc207eb",
      "name": "6. Log Invoice to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        400,
        -528
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{$('5. Extract Invoice Data with AI').first().json.output.issue_date}}",
            "amount": "={{$('5. Extract Invoice Data with AI').first().json.output.total_amount}}",
            "status": "pending",
            "company": "={{$('5. Extract Invoice Data with AI').first().json.output.bill_to_name}}",
            "rawText": "={{$('4. Prepare Text for AI').first().json.clean_text}}",
            "due_date": "={{$('5. Extract Invoice Data with AI').first().json.output.due_date}}",
            "invoice_number": "={{$('5. Extract Invoice Data with AI').first().json.output.invoice_number}}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": "YOUR_SHEET_NAME",
        "documentId": "YOUR_GOOGLE_SHEET_ID"
      },
      "typeVersion": 4.7
    },
    {
      "id": "67931763-dd8b-42e3-a2a5-c8bdf82e7e6f",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        192,
        -304
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"invoice_number\": \"20241007-001\",\n  \"issue_date\": \"2024-10-07\",\n  \"bill_to_name\": \"\u682a\u5f0f\u4f1a\u793e DRIX\",\n  \"total_amount\": 8800,\n  \"due_date\": \"2024-10-31\"\n}\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "1f145d04-12e7-4345-b67e-8621bf192800",
      "name": "9a. Update Status to Approved",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -416,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "approved",
            "invoice_number": "={{$json.invoice_id}}"
          },
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "invoice_number"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": "YOUR_SHEET_NAME",
        "documentId": "YOUR_GOOGLE_SHEET_ID"
      },
      "typeVersion": 4.7
    },
    {
      "id": "e9128567-5ea7-49b5-9ace-280e49026787",
      "name": "9b. Update Status to Rejected",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -416,
        208
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "rejected",
            "invoice_number": "={{$json.invoice_id}}"
          },
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "invoice_number"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": "YOUR_SHEET_NAME",
        "documentId": "YOUR_GOOGLE_SHEET_ID"
      },
      "typeVersion": 4.7
    },
    {
      "id": "bfc86cd9-f0d2-4c01-8cca-24388245c93e",
      "name": "7. Send Approval Request to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        624,
        -528
      ],
      "parameters": {
        "text": "=A new invoice requires your approval.\n\n*Company:* {{$('5. Extract Invoice Data with AI').first().json.output.bill_to_name}}\n*Amount:* {{$('5. Extract Invoice Data with AI').first().json.output.total_amount}}\n*Due Date:* {{$('5. Extract Invoice Data with AI').first().json.output.due_date}}\n\nPlease click the links below to approve or reject.\n\n*Approve:*\nhttps://YOUR_WEBHOOK_BASE_URL/webhook/approve?id={{$('5. Extract Invoice Data with AI').first().json.output.invoice_number}}\n\n*Reject:*\nhttps://YOUR_WEBHOOK_BASE_URL/webhook/reject?id={{$('5. Extract Invoice Data with AI').first().json.output.invoice_number}}",
        "select": "channel",
        "channelId": "YOUR_SLACK_CHANNEL_ID",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.3
    },
    {
      "id": "20ac3190-2d82-43e9-b47b-69133ceb3af6",
      "name": "8a. Extract Invoice ID",
      "type": "n8n-nodes-base.set",
      "position": [
        -640,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ded2aa43-262f-4f88-a1f2-0cb88777b8b0",
              "name": "invoice_id",
              "type": "string",
              "value": "={{$json.query.id}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2d72c14f-cd66-4d2e-84a7-23c522787d57",
      "name": "8b. Extract Invoice ID",
      "type": "n8n-nodes-base.set",
      "position": [
        -640,
        208
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d43309df-66c0-49fc-b3c2-8f095534e45f",
              "name": "invoice_id",
              "type": "string",
              "value": "={{$json.query.id}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "848586fb-b5c1-4595-abba-31de9a0f0497",
      "name": "GPT-4.1-mini Powered Invoice Processing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1696,
        -1632
      ],
      "parameters": {
        "width": 944,
        "height": 816,
        "content": "This workflow automates your invoice processing pipeline. It triggers on a new Gmail invoice, uses AI to extract data, logs it to a Google Sheet, and sends a Slack message with approval/rejection links.\n\n## Who is it for?\nThis template is perfect for small business owners, finance teams, and freelancers looking to eliminate manual data entry and streamline their accounts payable process.\n\n## How it works\n1.  **Trigger:** Starts when an email with a specific keyword (e.g., \"invoice\") arrives in Gmail.\n2.  **Extraction & AI:** It downloads the PDF, extracts the text, and uses a GPT-4.1-mini model to pull key details like invoice number, company, amount, and dates.\n3.  **Logging:** Appends the structured data to a Google Sheet with a `pending` status.\n4.  **Approval:** Sends a Slack message with the invoice data and unique approve/reject links.\n5.  **Update:** When a link is clicked, a Webhook updates the corresponding row in Google Sheets to `approved` or `rejected` and sends a confirmation to Slack.\n\n## Expected Google Sheet Structure\nYour Google Sheet should have the following columns to work with this template:\n- `invoice_number`\n- `company`\n- `amount`\n- `date`\n- `due_date`\n- `status`\n- `rawText`\n\n## How to set up\n1.  **Credentials:** Add your credentials for Gmail, OpenAI, Google Sheets, and Slack.\n2.  **Gmail Trigger:** Customize the search query (`q`) in the first node.\n3.  **Google/Slack:** Enter your Sheet ID/Name and Slack Channel ID in the relevant nodes.\n4.  **\u2757\ufe0f Activate Workflow & URLs:** This is a critical step. First, **activate the workflow** using the toggle in the top-right corner. Then, copy the **Production URLs** from the `Webhook (Approve)` and `Webhook (Reject)` nodes and paste them into the `7. Send Approval Request to Slack` node, replacing the `https://YOUR_WEBHOOK_BASE_URL` placeholder."
      },
      "typeVersion": 1
    },
    {
      "id": "32b5eb12-99c5-4a84-a0fb-5864d8e89e44",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -784
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 240,
        "content": "## Trigger\nThis node starts the workflow when an email matching the filter arrives.\n\n**Setup:** \n1. Add Gmail credentials.\n2. Change the search query `q` to your invoice keyword (e.g., \"invoice\")."
      },
      "typeVersion": 1
    },
    {
      "id": "b7352552-cca3-4f9c-99ef-d9441874d56f",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -592,
        -768
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 192,
        "content": "## Data Preparation\nThese nodes download the PDF from the email and extract its raw text content, preparing it for the AI."
      },
      "typeVersion": 1
    },
    {
      "id": "ca5ed7e7-6d1c-4990-aa8f-0e30743ae11e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -784
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 224,
        "content": "## AI Extraction & Logging\nAn AI model extracts structured data from the text, which is then appended to your Google Sheet.\n\n**Setup:**\n1. Add OpenAI & Google Sheets credentials.\n2. Enter your Sheet ID & Name."
      },
      "typeVersion": 1
    },
    {
      "id": "d1fd4b75-a743-4b6f-a361-468fce76e6c6",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        -800
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 240,
        "content": "## Slack Approval Request\nSends a message to Slack containing the invoice details and unique approval/rejection links.\n\n**Setup:**\n1. Add Slack credentials.\n2. Enter your Slack Channel ID.\n3. **IMPORTANT:** Replace the placeholder URLs with the Production URLs from the Webhook nodes."
      },
      "typeVersion": 1
    },
    {
      "id": "24adce38-a0b9-4b2f-8c38-d90e1cbca515",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -176
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 112,
        "content": "## Approval/Rejection Handling\nThese nodes listen for clicks on the Slack links. They update the Google Sheet status to \"approved\" or \"rejected\" and send a final confirmation message back to Slack."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "f44fad42-eccd-4aa1-a29b-3c654b13c6a5",
  "connections": {
    "Webhook (Reject)": {
      "main": [
        [
          {
            "node": "8b. Extract Invoice ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "5. Extract Invoice Data with AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Webhook (Approve)": {
      "main": [
        [
          {
            "node": "8a. Extract Invoice ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. Prepare Text for AI": {
      "main": [
        [
          {
            "node": "5. Extract Invoice Data with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8a. Extract Invoice ID": {
      "main": [
        [
          {
            "node": "9a. Update Status to Approved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8b. Extract Invoice ID": {
      "main": [
        [
          {
            "node": "9b. Update Status to Rejected",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Get Email Attachments": {
      "main": [
        [
          {
            "node": "3. Extract Text from PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Extract Text from PDF": {
      "main": [
        [
          {
            "node": "4. Prepare Text for AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "5. Extract Invoice Data with AI",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "1. New Invoice Email Received": {
      "main": [
        [
          {
            "node": "2. Get Email Attachments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9a. Update Status to Approved": {
      "main": [
        [
          {
            "node": "10a. Send Approval Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9b. Update Status to Rejected": {
      "main": [
        [
          {
            "node": "10b. Send Rejection Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Log Invoice to Google Sheet": {
      "main": [
        [
          {
            "node": "7. Send Approval Request to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Extract Invoice Data with AI": {
      "main": [
        [
          {
            "node": "6. Log Invoice to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}