{
  "id": "WCAyzxSt6yCROjq8",
  "name": "Automate Expense Reporting from Airtable to QuickBooks",
  "tags": [],
  "nodes": [
    {
      "id": "92e68aed-1a03-478b-89d4-5d94e98b3db0",
      "name": "Airtable Trigger",
      "type": "n8n-nodes-base.airtableTrigger",
      "position": [
        -120,
        1120
      ],
      "parameters": {
        "baseId": {
          "__rl": true,
          "mode": "id",
          "value": "appT0dprL0zCSuG45"
        },
        "tableId": {
          "__rl": true,
          "mode": "id",
          "value": "{YOUR_AIRTABLE_TABLE_ID}"
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerField": "Created",
        "authentication": "airtableTokenApi",
        "additionalFields": {}
      },
      "typeVersion": 1
    },
    {
      "id": "0b1822e8-1fcf-4ef0-872d-ec3b50d0ef9d",
      "name": "Search records",
      "type": "n8n-nodes-base.airtable",
      "position": [
        240,
        1120
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "{YOUR_AIRTABLE_BASE_ID}",
          "cachedResultUrl": "https://airtable.com/{YOUR_AIRTABLE_BASE_ID}",
          "cachedResultName": "airtable_expenses_dummy.csv"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "{YOUR_AIRTABLE_TABLE_ID}",
          "cachedResultUrl": "https://airtable.com/{YOUR_AIRTABLE_BASE_ID}/{YOUR_AIRTABLE_TABLE_ID}",
          "cachedResultName": "expense management"
        },
        "options": {},
        "operation": "search"
      },
      "typeVersion": 2.1
    },
    {
      "id": "6bd50650-7226-48ad-afe3-c2493e6c50f8",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        700,
        1120
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "dd2d7985-b436-4213-a3b9-56916c8f59b4",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.Status }}",
              "rightValue": "Approved"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2d50d1e9-8c4c-4dff-91cb-d39d0c1d0237",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1580,
        1580
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "5edab364-f81e-47e3-8da4-601b84b3ac19",
      "name": "Download File",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1560,
        780
      ],
      "parameters": {
        "url": "={{ $json['Receipt URL'] }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file",
              "outputPropertyName": "=Receipt"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "84784657-8fad-4e60-aa32-bdf75255ac2f",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        2800,
        760
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "02450b3c-81fa-4159-a910-730365a05dfd",
      "name": "Update record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        3840,
        760
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "{YOUR_AIRTABLE_BASE_ID}",
          "cachedResultUrl": "https://airtable.com/{YOUR_AIRTABLE_BASE_ID}",
          "cachedResultName": "airtable_expenses_dummy.csv"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "{YOUR_AIRTABLE_TABLE_ID}",
          "cachedResultUrl": "https://airtable.com/{YOUR_AIRTABLE_BASE_ID}/{YOUR_AIRTABLE_TABLE_ID}",
          "cachedResultName": "expense management"
        },
        "columns": {
          "value": {
            "id": "={{ $('Search records').item.json.id }}",
            "Status": "Done"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Receipt URL",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Receipt URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "dateTime",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Memo",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Memo",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "QBO Vendor ID",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "QBO Vendor ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "QBO Expense Account ID",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "QBO Expense Account ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "QBO Payment Account ID",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "QBO Payment Account ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Category",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Created",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Created",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Receipt Type",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Receipt Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Customer",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Customer",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "typeVersion": 2.1
    },
    {
      "id": "cb4a1747-f86b-427a-8325-113315392775",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        1300
      ],
      "parameters": {
        "color": 3,
        "width": 500,
        "height": 300,
        "content": "### Step 1: Airtable Trigger \ud83d\udea6\ud83d\udccb\n\nThis node triggers the workflow whenever there is a change in the **Created** column, effectively activating when new data is added.\n\nWhy this step is important:\n\n- \u23f0 Automatically starts the workflow on new entries.\n- \ud83d\udcc8 Monitors real-time changes for timely processing.\n- \ud83d\udd04 Ensures your automation responds instantly to new Airtable data.\n\nIt\u2019s the step that keeps your workflow synced with your Airtable updates. \ud83d\udd14\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d3c122f4-ce1a-4968-b57a-f8fa3ad261eb",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        60,
        780
      ],
      "parameters": {
        "width": 460,
        "height": 300,
        "content": "### Step 2: Airtable Search Records \ud83d\udd0d\ud83d\udccb\n\nThis node searches and retrieves all records from a specific Airtable table.\n\nWhy this step is important:\n\n- \ud83d\udd0e Gathers complete data from the table for processing.\n- \ud83d\udcca Enables further filtering, updating, or analysis within the workflow.\n- \ud83d\uddc2\ufe0f Provides a snapshot of all relevant records at once.\n\nIt\u2019s the step that collects your data foundation for the automation ahead. \ud83e\uddf1\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "2bc54880-2d88-41e6-9327-37dd97da3689",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        500,
        1280
      ],
      "parameters": {
        "color": 4,
        "width": 500,
        "height": 340,
        "content": "### Step 3: Status Check (If Node) \u2705\u274c\n\nThis node checks whether the **Status** field is set to **Approved**.\n\n- **True:** Status is Approved; workflow continues.\n- **False:** Status is not Approved; workflow can exit or take alternate action.\n\nWhy this step is important:\n\n- \u2714\ufe0f Ensures only approved items proceed in the workflow.\n- \ud83d\uded1 Prevents processing of unapproved or incomplete records.\n- \ud83d\udd04 Maintains workflow accuracy and efficiency.\n\nIt\u2019s the decision point that filters records based on their approval status. \ud83d\udea6\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "111d0402-84f5-4f09-b78d-b5b9ead43713",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1420,
        1260
      ],
      "parameters": {
        "width": 440,
        "height": 300,
        "content": "### Graceful Exit (No-Op Node) \ud83d\uded1\u2728\n\nThis **No Operation** node acts as a graceful exit for items whose **Status** is not Approved.\n\nWhy this step is important:\n\n- \ud83d\udee1\ufe0f Prevents further processing of unapproved records.\n- \ud83d\udd04 Ensures the workflow ends cleanly without errors.\n- \ud83e\uddf9 Maintains clear and organized workflow logic.\n\nIt\u2019s the safe stopping point that quietly ends the flow when no action is needed. \ud83d\udeaa\u2705\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b9847915-663e-4ec6-b815-71b09d28e687",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        440
      ],
      "parameters": {
        "color": 6,
        "width": 480,
        "height": 300,
        "content": "### Step 4: Download File from Receipt URL (HTTP Request) \ud83d\udce5\ud83d\udcbb\n\nThis node sends an **HTTP Request** to download the file from the provided **Receipt URL**.\n\nWhy this step is important:\n\n- \ud83d\udcc4 Retrieves the actual file (e.g., invoice, receipt) for further processing.\n- \ud83d\udd17 Ensures the workflow has access to the necessary document.\n- \u26a1 Enables downstream nodes to work with the downloaded file.\n\nIt\u2019s the step that pulls the file into your workflow for processing or storage. \ud83d\uddc2\ufe0f\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "6c6f6ede-b978-4351-abe3-cc6226ebc746",
      "name": "QBO-Create Expense",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2220,
        460
      ],
      "parameters": {
        "url": "https://sandbox-quickbooks.api.intuit.com/v3/company/{YOUR_QUICKBOOKS_COMPANY_ID}/purchase",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"PaymentType\": \"Cash\",\n  \"TxnDate\": \"{{$json['Date']}}\",\n  \"PrivateNote\": \"{{$json['Memo']}}\",\n  \"AccountRef\": { \"value\": \"{{$json['QBO Payment Account ID']}}\" },\n  \"EntityRef\": { \"type\": \"Vendor\", \"value\": \"{{$json['QBO Vendor ID']}}\" },\n  \"Line\": [\n    {\n      \"Amount\": {{$json['Amount']}},\n      \"DetailType\": \"AccountBasedExpenseLineDetail\",\n      \"AccountBasedExpenseLineDetail\": {\n        \"AccountRef\": { \"value\": \"{{$json['QBO Expense Account ID']}}\" }\n      }\n    }\n  ]\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "quickBooksOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "d6f91071-2044-4c56-b940-962a63765b60",
      "name": "QBO-Upload File",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3320,
        760
      ],
      "parameters": {
        "url": "https://sandbox-quickbooks.api.intuit.com/v3/company/{YOUR_QUICKBOOKS_COMPANY_ID}/upload?minorversion=65",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "file_content_01",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "Receipt"
            }
          ]
        },
        "nodeCredentialType": "quickBooksOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "b12dc68f-ef24-42a7-801c-54d03e729b67",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2060,
        100
      ],
      "parameters": {
        "color": 5,
        "width": 440,
        "height": 300,
        "content": "**Step 5 - Create Expense in QuickBooks (QBO) \ud83d\udcb8\ud83e\uddfe**\n\nThis node uses the **Create Expense** operation to add an expense in QuickBooks based on data from Airtable.\n\nWhy this step is important:\n\n- \ud83d\udcca Automatically records expenses from your Airtable data.\n- \ud83d\udd17 Links expenses to the correct accounts and vendors in QuickBooks.\n- \u26a1 Streamlines bookkeeping and financial tracking.\n\nIt\u2019s the step that turns raw expense data into an official QuickBooks record. \u2705\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e0617428-57bd-4fd6-b4cd-afec5931f363",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2640,
        920
      ],
      "parameters": {
        "width": 480,
        "height": 340,
        "content": "### Step 6: Merge Expense and File Data Node \ud83d\udd17\ud83d\udcc2\n\nThis node merges data from the **Create Expense** node and the **Download File** node.\n\nWhy this step is important:\n\n- \ud83d\udd04 Combines expense details with the corresponding file (receipt or invoice).\n- \ud83d\udcca Ensures all relevant information is packaged together for the next steps.\n- \u2699\ufe0f Maintains data integrity and prepares a unified dataset for further processing.\n\nIt\u2019s the step that consolidates expense and file data for smooth workflow continuation. \ud83e\udd1d\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "21f9dc2b-852c-43eb-9600-beb33c567bf7",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3120,
        500
      ],
      "parameters": {
        "color": 3,
        "width": 480,
        "height": 240,
        "content": "### Step 7: Upload File to QuickBooks (QBO Upload) \ud83d\udce4\ud83e\uddfe\n\nThis node uses the **Upload File** operation to attach the downloaded file (e.g., receipt or invoice) to QuickBooks.\n\nWhy this step is important:\n- \ud83d\udd17 Ensures proper documentation for bookkeeping and auditing.\n- \u26a1 Automates file management within QuickBooks, saving time and reducing errors.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5e7976bb-8812-407b-b79e-a67f2462e07c",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3680,
        940
      ],
      "parameters": {
        "color": 4,
        "width": 480,
        "height": 300,
        "content": "### Step 8: Update Airtable Record Status \u270f\ufe0f\u2705\n\nThis node updates the **Status** column of the Airtable records to **Done**.\n\nWhy this step is important:\n\n- \ud83d\udd04 Marks the completion of the workflow for each record.\n- \ud83d\udccb Provides clear visibility on processed items.\n- \u26a1 Ensures Airtable reflects the latest workflow status.\n\nIt\u2019s the step that closes the loop by updating the record\u2019s status to indicate successful processing. \ud83c\udfc1\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f270dc7e-492a-4f23-9f65-f4658c3aedde",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -180,
        20
      ],
      "parameters": {
        "color": 3,
        "width": 600,
        "height": 440,
        "content": "### Prerequisites \u2699\ufe0f\ud83d\udd17\n\n- Create and connect your **Airtable** account using a **Personal Access Token**.\n- Create a table with the following columns:\n  - **Status**\n  - **Receipt URL**\n  - **Amount**\n  - **Date**\n  - **Memo**\n  - **QBO Vendor ID**\n  - **QBO Expense Account ID**\n  - **QBO Payment Account ID**\n  - **Category**\n  - **Receipt Type**\n  - **Customer**\n- Connect your oauth2 Quickbooks credentials\n- Add your company id in the QBO nodes\nThese configurations ensure your Airtable is ready for seamless integration with QuickBooks and the workflow. \u2705\u2728\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a356ca74-915c-4349-9d68-c1a03cdc58f8",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1500,
        1800
      ],
      "parameters": {
        "width": 440,
        "height": 300,
        "content": "### Get in Touch\n\nPlease feel free to reachout to us, if you need any help in settin up this workflow.\n\nWe can also help customize workflow pet the use-case. \n\nReach out us at: getstarted@intuz.com\n\nWebsite: https://www.intuz.com/\n\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "71973fac-b373-4884-b5d0-f70497f5c2cb",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Download File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "QBO-Upload File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download File": {
      "main": [
        [
          {
            "node": "QBO-Create Expense",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Search records": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "QBO-Upload File": {
      "main": [
        [
          {
            "node": "Update record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Airtable Trigger": {
      "main": [
        [
          {
            "node": "Search records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "QBO-Create Expense": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}