{
  "id": "ZBcrVGqCZTFn34Gjsryiw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Proactive company budget controller Bexio and GoogleSheets",
  "tags": [],
  "nodes": [
    {
      "id": "9d0bc3d2-3f08-4c12-a423-360f8d1d5b0e",
      "name": "Set Offset",
      "type": "n8n-nodes-base.set",
      "position": [
        1232,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "21fa8709-a9bc-45d4-8dbb-ad9789367221",
              "name": "offset",
              "type": "number",
              "value": "={{$json[\"new_offset\"] || 0}}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "7c5f7c4a-25d9-4098-9804-e767f60c1468",
      "name": "Add Offset",
      "type": "n8n-nodes-base.set",
      "position": [
        2000,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c2d5d63e-a2b0-4bad-a9fd-faa3eb65810f",
              "name": "new_offset",
              "type": "number",
              "value": "={{ $('Set Offset').item.json.offset + $('Batch Size').item.json.batchSize}}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "bf4aa503-c994-4704-a073-8d8051392328",
      "name": "Update Records",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1664,
        160
      ],
      "parameters": {
        "columns": {
          "value": {
            "ID": "={{ $json.id }}",
            "Date": "={{ DateTime.fromISO($json.date).toFormat('yyyy-MM-dd') }}",
            "Amount": "={{ $json.amount }}",
            "Debit ID": "={{ $json.debit_account_id }}",
            "Credit ID": "={{ $json.credit_account_id }}",
            "Sync Date": "={{ DateTime.now().toFormat('yyyy-MM-dd') }}",
            "Currency ID": "={{ $json.currency_id }}",
            "Description": "={{ $json.description }}",
            "Date Formated": "={{ DateTime.fromISO($json.date).toFormat('MM yyyy') }}",
            "Year Formatted": "={{ DateTime.fromISO($json.date).toFormat('yyyy') }}",
            "Conversion factor": "={{ $json.currency_factor }}",
            "Amount in basic currency": "={{ $json.base_currency_amount }}"
          },
          "schema": [
            {
              "id": "ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Debit ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Debit ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Credit ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Credit ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Currency ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Conversion factor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Conversion factor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount in basic currency",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount in basic currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Year Formatted",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Year Formatted",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date Formated",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date Formated",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sync Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Sync Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit#gid=0",
          "cachedResultName": "Journal"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit?usp=drivesdk",
          "cachedResultName": "Accounting journal (n8n template)"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "e1378ea8-6d9d-4133-89c8-84be927c0845",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 464,
        "content": "## Initial settings"
      },
      "typeVersion": 1
    },
    {
      "id": "37b9dee9-5c1b-412d-b1a7-c90ee4bd977d",
      "name": "Delay",
      "type": "n8n-nodes-base.wait",
      "position": [
        1840,
        160
      ],
      "parameters": {
        "amount": 2
      },
      "executeOnce": true,
      "typeVersion": 1.1
    },
    {
      "id": "1348be14-dcb8-45fe-a9f4-84eec811ee73",
      "name": "Get Records",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1456,
        160
      ],
      "parameters": {
        "url": "=https://api.bexio.com/3.0/accounting/journal",
        "options": {
          "response": {
            "response": {}
          }
        },
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "from",
              "value": "2025-01-01"
            },
            {
              "name": "to",
              "value": "2025-12-31"
            },
            {
              "name": "=limit",
              "value": "=1000"
            },
            {
              "name": "=offset",
              "value": "={{ $json.offset }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2
    },
    {
      "id": "7ba55437-f07f-4532-ac7c-d090b6cfaf8d",
      "name": "Batch Size",
      "type": "n8n-nodes-base.set",
      "position": [
        736,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ebdf097d-9e7e-452b-9376-b5a796fd2239",
              "name": "batchSize",
              "type": "number",
              "value": 1000
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3ba9d765-3124-4c7f-9f34-686e60a45b1d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 1440,
        "height": 464,
        "content": "## Update accounting records Bexio to Google Sheets"
      },
      "typeVersion": 1
    },
    {
      "id": "6ceb6bf9-822a-4b64-8c41-936d3f4a4388",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        0
      ],
      "parameters": {
        "width": 640,
        "height": 1088,
        "content": "**This n8n template allows you to automatically monitor your company's budget by comparing live Bexio accounting data against targets defined in Google Sheets, sending automated weekly email reports.**\n\nFinancial overspending often goes unnoticed until it's too late. This workflow transforms reactive accounting into **proactive management** by automatically calculating monthly actuals and flagging budget overages in real-time, eliminating the need for manual spreadsheet updates.\n\n## How it works\n* Data Extraction: Uses a recursive pagination loop to fetch all journal entries from the Bexio API.\n* Financial Logic: Aggregates costs per account by merging and calculating the delta between Debits and Credits.\n* Budget Comparison: Reads your target thresholds from Google Sheets and compares them against calculated monthly actuals.\n* Automated Reporting: Generates a summary report and sends it via Gmail periodically.\n\n## Setup steps\n- [ ] Credentials: Connect your Bexio (Bearer Token), Google Sheets (OAuth2), and Gmail accounts.\n- [ ] Spreadsheet Config: Clone the template and set you metrics and monthly budgets in the \"Budgets\" sheet. The \"Accounts\" sheet contains sample records. The records will be populated from Bexio automatically. \n- [ ] Gmail: Enter an email address for reporting purposes in the field \"To\" inside Gmail node.\n\n## Customization tips\n* Switch the Gmail node for Slack or Microsoft Teams for instant push notifications.\n* Change schedule to bi-weekly or daily according to your needs. \n\n## Requirements\n* Bexio account with API access.\n* Google Sheets for budget storage.\n* Gmail account for sending reports."
      },
      "typeVersion": 1
    },
    {
      "id": "b6ed1653-a432-4d09-9ede-51a50fb7c89f",
      "name": "Read Budgets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        656,
        880
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1462771045,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit#gid=1462771045",
          "cachedResultName": "Budgets"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit?usp=drivesdk",
          "cachedResultName": "Accounting journal (n8n template)"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "735a28d8-530d-4874-9df6-5b1a1ccf803e",
      "name": "Get Debits",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1200,
        1280
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json['Account ID'] }}",
              "lookupColumn": "Debit ID"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit#gid=0",
          "cachedResultName": "Journal"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit?usp=drivesdk",
          "cachedResultName": "Accounting journal (n8n template)"
        },
        "combineFilters": "OR"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "14df45e7-63d2-49dc-a320-2b29e54a8b23",
      "name": "Get Credits",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1200,
        1456
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json['Account ID'] }}",
              "lookupColumn": "Credit ID"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit#gid=0",
          "cachedResultName": "Journal"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1ZnaXFqOhcrgMptM2K8k-W0VZTxgyL99_D569GiwTZZk/edit?usp=drivesdk",
          "cachedResultName": "Accounting journal (n8n template)"
        },
        "combineFilters": "OR"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "003f5228-4279-45bb-92fb-4dffcb17bee9",
      "name": "Calculate Credits",
      "type": "n8n-nodes-base.code",
      "position": [
        1360,
        1280
      ],
      "parameters": {
        "jsCode": "// detect year from first item or default to current year\nconst year = items[0]?.json[\"Date Formated\"]?.split(\" \")[1] || new Date().getFullYear();\n\n// initialize 12 months with 0\nconst totals = Object.fromEntries(\n  Array.from({ length: 12 }, (_, i) => [\n    `${String(i + 1).padStart(2, \"0\")} ${year}`, 0\n  ])\n);\n\n// sum amounts if input is not empty\nfor (const { json } of items || []) {\n  const key = json[\"Date Formated\"];\n  if (key && totals.hasOwnProperty(key)) {\n    totals[key] += Number(json[\"Amount in basic currency\"]) || 0;\n  }\n}\n\n// return 1 item with all months\nreturn [{ json: Object.fromEntries(\n  Object.entries(totals).map(([month, total]) => [month, +total.toFixed(2)])\n) }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "216b8051-60c8-4b8a-8ccb-aa73d294d8d0",
      "name": "Calculate debit",
      "type": "n8n-nodes-base.code",
      "position": [
        1360,
        1456
      ],
      "parameters": {
        "jsCode": "// detect year from first item or default to current year\nconst year = items[0]?.json[\"Date Formated\"]?.split(\" \")[1] || new Date().getFullYear();\n\n// initialize 12 months with 0\nconst totals = Object.fromEntries(\n  Array.from({ length: 12 }, (_, i) => [\n    `${String(i + 1).padStart(2, \"0\")} ${year}`, 0\n  ])\n);\n\n// sum amounts if input is not empty\nfor (const { json } of items || []) {\n  const key = json[\"Date Formated\"];\n  if (key && totals.hasOwnProperty(key)) {\n    totals[key] += Number(json[\"Amount in basic currency\"]) || 0;\n  }\n}\n\n// return 1 item with all months\nreturn [{ json: Object.fromEntries(\n  Object.entries(totals).map(([month, total]) => [month, +total.toFixed(2)])\n) }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "5ef10109-0ad8-41aa-aa24-3c5b4bd35af2",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        912,
        880
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "0b90b1b0-ff9c-4dec-bb75-7fb5fd2f2ec7",
      "name": "Merge Credits/Debits",
      "type": "n8n-nodes-base.merge",
      "position": [
        1568,
        1296
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "4d9c877c-8219-4527-b1e1-ccc9d99fb49c",
      "name": "Calculate Costs",
      "type": "n8n-nodes-base.code",
      "position": [
        1712,
        1296
      ],
      "parameters": {
        "jsCode": "const [credit, debit] = items.map(i => i.json);\n\nconst result = Object.fromEntries(\n  Object.keys(credit).map(month => [month, +(credit[month] - (debit[month] || 0)).toFixed(2)])\n);\n\nreturn [{ json: result }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a10b7090-106b-4368-87f6-d7c26e492bf9",
      "name": "Add Budgets",
      "type": "n8n-nodes-base.merge",
      "position": [
        1904,
        912
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "57d20597-f0b1-482e-95f8-6a9e1a9a519d",
      "name": "Check Budgets",
      "type": "n8n-nodes-base.code",
      "position": [
        2064,
        912
      ],
      "parameters": {
        "jsCode": "const actuals = items[1].json;\nconst budget = items[0].json;\n\n// dynamic key from Metric\nconst key = items[0].json.Metric || \"messages\";\n\n// generate messages if actual > budget\nlet result = Object.keys(budget)\n  .filter(month => actuals[month] > budget[month])\n  .map(month => `Budget exceeded in ${month} - budget: ${budget[month]}, actual: ${actuals[month]}`);\n\n// fallback if empty\nif (result.length === 0) {\n  result = [\"All costs within the budget\"];\n}\n\n// return single item with dynamic key\nreturn [{ json: { [key]: result } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "187500f9-204f-439f-a489-eb74f6ba5ba0",
      "name": "Compose Report",
      "type": "n8n-nodes-base.code",
      "position": [
        1184,
        544
      ],
      "parameters": {
        "jsCode": "const input = items.map(i => i.json);\n\nlet body = \"Budget Report:\\n\\n\";\n\nfor (const section of input) {\n  for (const [metric, messages] of Object.entries(section)) {\n    body += `${metric}:\\n`;\n    for (const msg of messages) {\n      body += `- ${msg}\\n`;\n    }\n    body += \"\\n\"; // add extra line between sections\n  }\n}\n\n// return single item with email body\nreturn [{ json: { email_body: body.trim() } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1f8f1484-d9e0-409b-881d-edbb189246e8",
      "name": "Send Report",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1360,
        544
      ],
      "parameters": {
        "message": "={{ $json.email_body }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Budget Report {{ $now.format(\"dd/LL/yyyy\") }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0d8d55ea-7c9c-4765-8c7f-ba70df930756",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        1200
      ],
      "parameters": {
        "color": 7,
        "width": 1872,
        "height": 464,
        "content": "## Calculate costs for each period based on accounting records"
      },
      "typeVersion": 1
    },
    {
      "id": "6e98e233-a25c-498c-848a-954e335ce469",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 1872,
        "height": 272,
        "content": "## Send final reports"
      },
      "typeVersion": 1
    },
    {
      "id": "01b2caf9-8ec9-45a5-bf36-cb86834e71b9",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 1872,
        "height": 384,
        "content": "## Compare budgets to actual costs"
      },
      "typeVersion": 1
    },
    {
      "id": "a823f709-c1ef-45c6-a766-e7d829ddafc5",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        576,
        160
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "87f7206e-cfc5-4c2e-b4f5-6d646b830b5f",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        1120
      ],
      "parameters": {
        "color": 5,
        "width": 640,
        "height": 544,
        "content": "## Example report\n\nBudget Report:\n\nIT costs:\n- Budget exceeded in 04 2025 - budget: 200, actual: 420\n\n\nRentals:\n- All costs within the budget\n\n\nYour custom metric\n- Report if budget exceeded any month"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "d246032d-d458-4ca2-b58c-84135e775407",
  "connections": {
    "Delay": {
      "main": [
        [
          {
            "node": "Add Offset",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Offset": {
      "main": [
        [
          {
            "node": "Set Offset",
            "type": "main",
            "index": 0
          },
          {
            "node": "Read Budgets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Batch Size": {
      "main": [
        [
          {
            "node": "Set Offset",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Debits": {
      "main": [
        [
          {
            "node": "Calculate Credits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Offset": {
      "main": [
        [
          {
            "node": "Get Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Budgets": {
      "main": [
        [
          {
            "node": "Check Budgets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Credits": {
      "main": [
        [
          {
            "node": "Calculate debit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Records": {
      "main": [
        [
          {
            "node": "Update Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Budgets": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Budgets": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compose Report": {
      "main": [
        [
          {
            "node": "Send Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Records": {
      "main": [
        [
          {
            "node": "Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Costs": {
      "main": [
        [
          {
            "node": "Add Budgets",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Calculate debit": {
      "main": [
        [
          {
            "node": "Merge Credits/Debits",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Compose Report",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Add Budgets",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Debits",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Credits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Batch Size",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Credits": {
      "main": [
        [
          {
            "node": "Merge Credits/Debits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Credits/Debits": {
      "main": [
        [
          {
            "node": "Calculate Costs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}