{
  "id": "omGegE9vPd6v03RM",
  "name": "Invoice Generation System",
  "tags": [],
  "nodes": [
    {
      "id": "18b67cf7-0177-424a-b834-3dd143d177a8",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        112,
        -384
      ],
      "parameters": {
        "path": "your-webhook-path",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "536218fd-ccb3-465d-9e98-ad4171e464dc",
      "name": "Create a record1",
      "type": "n8n-nodes-base.airtable",
      "position": [
        112,
        48
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultName": "Your Airtable Base"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_INVOICE_TABLE_ID",
          "cachedResultName": "Factura"
        },
        "columns": {
          "value": {
            "Date": "={{ $('Webhook').first().json.body.date }}",
            "Client": "={{ $('Webhook').first().json.body.clientId }}",
            "Service": "={{ $('Formatting Data').first().json.id }}",
            "Invoice #": "={{ $('Generate Invoice #').item.json.nextInvoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice #",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Invoice #",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Client",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Service",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Service",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total_Taxable_Base",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Total_Taxable_Base",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total VAT",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Total VAT",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Retention",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Total Retention",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Total",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Invoice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total_Taxable_Base (from Servicio)",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Total_Taxable_Base (from Servicio)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total (from Servicio)",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Total (from Servicio)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Service Description",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Service Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total VAT (from Servicio)",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Total VAT (from Servicio)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Retention (from Servicio)",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Total Retention (from Servicio)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "typecast": true
        },
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "fc3fc580-c2ae-4eaa-9434-18bab1dd1642",
      "name": "Add Service to DB",
      "type": "n8n-nodes-base.airtable",
      "position": [
        560,
        -384
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultName": "Your Airtable Base"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SERVICE_TABLE_ID",
          "cachedResultName": "Servicio"
        },
        "columns": {
          "value": {
            "VAT": "={{ $json.vat }}",
            "Units": "={{ $json.units }}",
            "Value": "={{ $json.price }}",
            "Retention": "={{ $json.retention }}",
            "Description": "={{ $json.description }}"
          },
          "schema": [
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Value",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Value",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Units",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Units",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "VAT",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "VAT",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Retention",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Retention",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Total",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Factura",
              "type": "array",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Factura",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "3e0cc576-d6e4-49ef-ae96-1e72451a0e45",
      "name": "Split Services",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        336,
        -384
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "body.services"
      },
      "typeVersion": 1
    },
    {
      "id": "e1c5aa9f-2687-493f-b719-8250f73ded7a",
      "name": "Formatting Data",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        -384
      ],
      "parameters": {
        "jsCode": "// n8n Code Node - Transform Airtable data to array format with formatting\n\nconst items = $input.all();\n\nconst ids = [];\nconst values = [];\n\nfor (const item of items) {\n  const data = item.json;\n  ids.push(data.id);\n\n  const fields = data.fields;\n\n  const formattedValue = fields.Value.toFixed(2) + '\u20ac';\n  const formattedUnits = fields.Units;\n  const formattedVAT = fields.VAT + '%';\n  const formattedRetention = fields.Retention === 0 ? '0%' : '-' + fields.Retention + '%';\n  const formattedTotal = fields.Total.toFixed(2) + '\u20ac';\n\n  const valueArray = [\n    fields.Description,\n    formattedValue,\n    formattedUnits,\n    formattedVAT,\n    formattedRetention,\n    formattedTotal\n  ];\n\n  values.push(valueArray);\n}\n\nreturn {\n  json: {\n    id: ids,\n    values: {\n      values: values\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "fd0eb607-53b0-4c2c-b4e5-a9a9a9be49fd",
      "name": "Get Previous Invoices",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1008,
        -384
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultName": "Your Airtable Base"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_INVOICE_TABLE_ID",
          "cachedResultName": "Factura"
        },
        "options": {},
        "operation": "search"
      },
      "typeVersion": 2.1,
      "alwaysOutputData": true
    },
    {
      "id": "061b0353-3969-4111-b3bc-63deb1be87e1",
      "name": "Generate Invoice #",
      "type": "n8n-nodes-base.code",
      "position": [
        112,
        -176
      ],
      "parameters": {
        "jsCode": "// n8n Code Node - Invoice Number Generator (JavaScript)\n\nconst currentYear = new Date().getFullYear();\nconst invoices = $input.all();\n\nlet maxNumber = 0;\n\nfor (const invoice of invoices) {\n  const invoiceNum = invoice.json['Invoice #'];\n\n  if (invoiceNum) {\n    const parts = invoiceNum.split('-');\n\n    if (parts.length === 2) {\n      const year = parseInt(parts[0]);\n      const number = parseInt(parts[1]);\n\n      if (year === currentYear && !isNaN(number)) {\n        maxNumber = Math.max(maxNumber, number);\n      }\n    }\n  }\n}\n\nconst nextNumber = maxNumber + 1;\nconst paddedNumber = nextNumber.toString().padStart(4, '0');\nconst nextInvoiceNumber = `${currentYear}-${paddedNumber}`;\n\nreturn {\n  json: {\n    nextInvoiceNumber: nextInvoiceNumber,\n    year: currentYear,\n    sequenceNumber: nextNumber,\n    lastInvoiceNumber: maxNumber > 0 ? `${currentYear}-${maxNumber.toString().padStart(4, '0')}` : 'None'\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "81ac9e60-1449-4dff-b09a-c8e5e91e1d1c",
      "name": "Copy Invoice Template",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        336,
        -176
      ],
      "parameters": {
        "name": "={{ $json.nextInvoiceNumber }}_Factura",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEETS_TEMPLATE_FILE_ID"
        },
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_DRIVE_OUTPUT_FOLDER_ID"
        },
        "operation": "copy",
        "sameFolder": false
      },
      "typeVersion": 3
    },
    {
      "id": "b5f35fce-d2c9-461e-a581-8b3250748d99",
      "name": "Add Services to Invoice",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        560,
        -176
      ],
      "parameters": {
        "url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $json.id }}/values/A19:append",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $('Formatting Data').first().json.values }}",
        "sendBody": true,
        "sendQuery": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "valueInputOption",
              "value": "USER_ENTERED"
            },
            {
              "name": "insertDataOption",
              "value": "INSERT_ROWS"
            }
          ]
        },
        "nodeCredentialType": "googleSheetsOAuth2Api"
      },
      "typeVersion": 4.3
    },
    {
      "id": "7aeabe32-d087-424a-a12e-89162500ea68",
      "name": "Get Client Info",
      "type": "n8n-nodes-base.airtable",
      "position": [
        784,
        -176
      ],
      "parameters": {
        "id": "={{ $('Webhook').first().json.body.clientId }}",
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultName": "Your Airtable Base"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_CLIENT_TABLE_ID",
          "cachedResultName": "Client"
        },
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "4f80ca1f-631e-4cfc-8a12-c433d1b8996c",
      "name": "Add Client Info",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1008,
        -176
      ],
      "parameters": {
        "url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $('Add Services to Invoice').item.json.spreadsheetId }}:batchUpdate",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"requests\": [\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"invoice_date\",\n        \"replacement\": \"{{ $('Webhook').first().json.body.date }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"invoice_number\",\n        \"replacement\": \"{{ $('Generate Invoice #').item.json.nextInvoiceNumber }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"billingName\",\n        \"replacement\": \"{{ $json.Name }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"billingId\",\n        \"replacement\": \"{{ $json.ID }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"billingAddress\",\n        \"replacement\": \"{{ $json.Address }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"billingCity\",\n        \"replacement\": \"{{ $json.City }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"billingCountry\",\n        \"replacement\": \"{{ $json.Country }}\",\n        \"matchEntireCell\": true\n      }\n    }\n\n  ]\n} ",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSheetsOAuth2Api"
      },
      "typeVersion": 4.3
    },
    {
      "id": "c5aa8cf1-76f9-4f3d-8083-58da584563d4",
      "name": "Create a record1 (template)",
      "type": "n8n-nodes-base.airtable",
      "position": [
        112,
        48
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultName": "Your Airtable Base"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_INVOICE_TABLE_ID",
          "cachedResultName": "Factura"
        },
        "columns": {
          "value": {
            "Date": "={{ $('Webhook').first().json.body.date }}",
            "Client": "={{ $('Webhook').first().json.body.clientId }}",
            "Service": "={{ $('Formatting Data').first().json.id }}",
            "Invoice #": "={{ $('Generate Invoice #').item.json.nextInvoiceNumber }}"
          },
          "schema": [
            {
              "id": "Invoice #",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Invoice #",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Client",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Service",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Service",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Invoice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "typecast": true
        },
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "687a7047-3202-4992-a20f-f4e268e31f2e",
      "name": "Add Invoice Summary Info",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        336,
        48
      ],
      "parameters": {
        "url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $('Add Services to Invoice').item.json.spreadsheetId }}:batchUpdate",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"requests\": [\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"total_taxable_base\",\n        \"replacement\": \"{{ Number($json.fields.Total_Taxable_Base).toFixed(2) + '\u20ac' }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"total_vat\",\n        \"replacement\": \"{{ Number($json.fields['Total VAT']).toFixed(2) + '\u20ac' }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"total_retention\",\n        \"replacement\": \"{{'-'+ Number($json.fields['Total Retention']).toFixed(2) + '\u20ac' }}\",\n        \"matchEntireCell\": true\n      }\n    },\n    {\n      \"findReplace\": {\n        \"sheetId\": \"0\",\n        \"find\": \"total_total\",\n        \"replacement\": \"{{ Number($json.fields.Total).toFixed(2) + '\u20ac' }}\",\n        \"matchEntireCell\": true\n      }\n    }\n\n  ]\n} ",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSheetsOAuth2Api"
      },
      "typeVersion": 4.3
    },
    {
      "id": "26ba7f66-02c0-4160-8766-fde3e9af4ad6",
      "name": "Share file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        560,
        48
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.spreadsheetId }}"
        },
        "options": {},
        "operation": "share",
        "permissionsUi": {
          "permissionsValues": {
            "role": "reader",
            "type": "anyone"
          }
        }
      },
      "typeVersion": 3
    },
    {
      "id": "d4f2a694-b239-48ed-a1b6-6da33e66c30e",
      "name": "Update record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        784,
        48
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultName": "Your Airtable Base"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_INVOICE_TABLE_ID",
          "cachedResultName": "Factura"
        },
        "columns": {
          "value": {
            "id": "={{ $('Create a record1').item.json.id }}",
            "Invoice": "=[{\"url\":\"https://docs.google.com/spreadsheets/d/{{ $('Add Invoice Summary Info').item.json.spreadsheetId }}/export?format=pdf\"}]"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true
            },
            {
              "id": "Invoice",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Invoice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "typeVersion": 2.1
    },
    {
      "id": "c55694e2-5220-4cfd-aceb-36ae2ca08d39",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -912,
        -368
      ],
      "parameters": {
        "width": 928,
        "height": 720,
        "content": "# Automated Invoice Generator (Airtable + Google Sheets)\n\nThis workflow completely automates the invoicing process by turning raw JSON data into a formatted PDF and syncing it with your CRM. It specifically handles **multiple line items**, ensuring detailed breakdowns on your invoices.\n\n### How it works\n1. **Webhook Trigger:** Receives a payload containing a Client ID and a list of Services (items).\n2. **Line Item Processing:** Splits the list of services and creates individual records in your Airtable \"Services\" table.\n3. **Template Generation:** Duplicates a master Google Sheet template, fills in the client details and dynamic service rows, and calculates totals.\n4. **CRM Sync:** Creates a master \"Invoice\" record in Airtable, generates a shareable PDF link from Drive, and attaches the file back to the Airtable record.\n\n### Setup steps\n1. **Airtable:** Create 3 tables (Clients, Invoices, Services) and link them.\nAirtable Template: [https://airtable.com/appUL5P7KN2Kqsgsf/shr5vCMwg2o4Z5wZI](https://airtable.com/appUL5P7KN2Kqsgsf/shr5vCMwg2o4Z5wZI)\n2. **Google Drive:** Create a Google Sheet template with placeholders (e.g., `{{clientName}}`).\nGoogle Sheets Template: [https://docs.google.com/spreadsheets/d/1XF9vcbsgYqDDgQwBn4RNtnzCkBjbk3jmKU7MBgIXtbo/edit?usp=sharing](https://docs.google.com/spreadsheets/d/1XF9vcbsgYqDDgQwBn4RNtnzCkBjbk3jmKU7MBgIXtbo/edit?usp=sharing)\n3. **Credentials:** Connect your Google Drive and Airtable credentials in the respective nodes.\n4. **Webhook:** Ensure your frontend sends a JSON body with `clientId` and an array of `services`.\n\n### \ud83d\udc4b Need help building this? Want to automate & scale your business?\nI help businesses automate their \"boring work\" so they can focus on sales.\n- https://www.linkedin.com/in/sergiomedinah/\n- https://sergio-medina.com/"
      },
      "typeVersion": 1
    },
    {
      "id": "b0179c1c-51af-48b7-b6c7-af62cae8e6f1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1200,
        -400
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "content": "## Process Line Items\nIterates through the incoming list of services, logging each one into the Airtable \"Services\" table and preparing the data for the invoice."
      },
      "typeVersion": 1
    },
    {
      "id": "2636e5e0-c08b-4501-842d-35a4026c0806",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1200,
        -208
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "content": "## Fill Template\nCalculates the new invoice number, duplicates the Google Sheet template, and maps the service rows and client details into the file."
      },
      "typeVersion": 1
    },
    {
      "id": "1c027410-a3d7-4641-842d-cc25be66df3a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1200,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "content": "## Finalize & Sync\nCreates the master Invoice record in Airtable, generates a public PDF link from Google Drive, and attaches the final document to the CRM record."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "95422eca-c691-4c4c-b08e-850e118a3b15",
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Split Services",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Share file": {
      "main": [
        [
          {
            "node": "Update record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Services": {
      "main": [
        [
          {
            "node": "Add Service to DB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Client Info": {
      "main": [
        [
          {
            "node": "Create a record1 (template)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatting Data": {
      "main": [
        [
          {
            "node": "Get Previous Invoices",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Client Info": {
      "main": [
        [
          {
            "node": "Add Client Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Service to DB": {
      "main": [
        [
          {
            "node": "Formatting Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Invoice #": {
      "main": [
        [
          {
            "node": "Copy Invoice Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Copy Invoice Template": {
      "main": [
        [
          {
            "node": "Add Services to Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Previous Invoices": {
      "main": [
        [
          {
            "node": "Generate Invoice #",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Services to Invoice": {
      "main": [
        [
          {
            "node": "Get Client Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Invoice Summary Info": {
      "main": [
        [
          {
            "node": "Share file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a record1 (template)": {
      "main": [
        [
          {
            "node": "Add Invoice Summary Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}