{
  "id": "MeQW2OGJvNbxJY6Q",
  "name": "AI API Expense Tracker- FAL, APIFY and Open Router",
  "tags": [],
  "nodes": [
    {
      "id": "00ae67c6-bed3-41b1-a5d4-e9336710ea31",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 768,
        "content": "## Expense Tracker- FAL, APIFY and Open Router\n\n### How it works\n\nThis workflow runs on a schedule to track account expenses and remaining credits across FAL AI, OpenRouter, and Apify. It queries each provider API in sequence, consolidates the returned usage data with a JavaScript code node, and sends the resulting summary to Telegram.\n\n### Setup steps\n\n- Configure the Schedule Trigger with the desired checking frequency.\n- Add valid API authentication for the FAL AI billing request, OpenRouter credits request, and Apify usage request in their respective HTTP Request nodes.\n- Configure the Telegram node with bot credentials and the target chat ID for receiving the expense summary.\n- Review the JavaScript code node to ensure it matches the response formats returned by the three provider APIs.\n\n### Customization\n\nYou can adjust the schedule, add more provider credit endpoints, change the summary formatting in the JavaScript node, or route alerts to another notification channel instead of Telegram."
      },
      "typeVersion": 1
    },
    {
      "id": "86e621b3-8cfc-4e74-a0d8-c23a0a08bf8c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        0
      ],
      "parameters": {
        "color": 7,
        "height": 368,
        "content": "## Scheduled start\n\nStarts the workflow on a configured schedule so expense and credit balances can be checked automatically."
      },
      "typeVersion": 1
    },
    {
      "id": "dab7f67a-838e-4857-82da-785f5ed46753",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 304,
        "content": "## Fetch service credits\n\nCalls the FAL AI, OpenRouter, and Apify APIs in sequence to retrieve current billing, credits, and usage information from each service."
      },
      "typeVersion": 1
    },
    {
      "id": "5441a46c-0899-43bf-97b7-746399946807",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1504,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 320,
        "content": "## Format and notify\n\nCombines the collected API responses in JavaScript, prepares a readable summary, and sends it as a Telegram text message."
      },
      "typeVersion": 1
    },
    {
      "id": "64047cdc-8642-460b-8bb5-13046e2440e4",
      "name": "Fetch FAL AI Credits",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        880,
        208
      ],
      "parameters": {
        "url": "https://api.fal.ai/v1/account/billing?expand=credits",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Key YOUR API Key"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f8b1de4a-d0ee-4d2b-bba2-3022f987791e",
      "name": "Fetch Open Router Credits",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1120,
        208
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/credits",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE API Key"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "cf6ede28-a305-4873-8753-3ec1ddc908e8",
      "name": "Fetch APIFY Monthly Usage",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1328,
        208
      ],
      "parameters": {
        "url": "https://api.apify.com/v2/users/me/usage/monthly",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "YOUR API Key"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f59b976b-7b78-4f6d-8c2e-5dd96acf7e30",
      "name": "Collect Data in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        1552,
        208
      ],
      "parameters": {
        "jsCode": "// 1. Safely collect ALL data from the workflow\nconst jsons = [];\ntry { jsons.push($items('FAL AI Credits')[0]?.json); } catch(e) {}\ntry { jsons.push($items('Open Router Credits')[0]?.json); } catch(e) {}\ntry { jsons.push($items('APIFY Credits')[0]?.json); } catch(e) {}\n\n// 2. DEEP SEARCH FUNCTION: Recursively hunts for exact keys\nfunction findValue(keys) {\n  let result = null;\n  function search(obj) {\n    if (result !== null) return;\n    if (typeof obj !== 'object' || obj === null) return;\n    for (let k of keys) {\n      if (obj[k] !== undefined && obj[k] !== null) {\n        let val = parseFloat(obj[k]);\n        if (!isNaN(val)) { result = val; return; }\n      }\n    }\n    for (let k in obj) search(obj[k]);\n  }\n  jsons.forEach(search);\n  return result;\n}\n\n// 3. Extract exact values from the proper billing endpoints\n// FAL AI\nconst falBalance = findValue(['current_balance']);\n\n// OpenRouter (/api/v1/credits returns 'total_credits' and 'total_usage')\nconst orTotalCredits = findValue(['total_credits']);\nconst orTotalUsage   = findValue(['total_usage']);\n\n// Apify (/v2/users/me/usage/monthly returns USD amounts directly)\n// We look for 'totalUsageCreditsUsd' (Used) and 'monthlyUsageLimitUsd' or 'maxMonthlyUsageUsd' (Plan)\nconst apifyUsedUsd = findValue(['totalUsageCreditsUsd', 'totalUsageCreditsUsdAfterVolumeDiscount']);\n// To get the plan limit dynamically, we check the general limits (usually stored as maxMonthlyUsageUsd)\nconst apifyPlanUsd = findValue(['maxMonthlyUsageUsd', 'monthlyUsageLimitUsd', 'subscriptionLimitUsd']) ?? 29.00; // Apify usually hides the total plan limit in the /usage endpoint, but we grab the used USD directly.\n\n// 4. Calculate & Format Strings\nconst falStr = falBalance !== null ? `$${falBalance.toFixed(2)}` : 'N/A';\n\n// OpenRouter math: (total_credits - total_usage)\nlet orBalanceStr = 'N/A';\nlet orUsedStr    = 'N/A';\nif (orTotalCredits !== null && orTotalUsage !== null) {\n  orBalanceStr = `$${(orTotalCredits - orTotalUsage).toFixed(2)}`;\n  orUsedStr    = `$${orTotalUsage.toFixed(4)}`;\n}\n\n// Apify formatting\nconst apUsedStr = apifyUsedUsd !== null ? `$${apifyUsedUsd.toFixed(2)}` : 'N/A';\nconst apPlanStr = apifyPlanUsd !== null ? `$${apifyPlanUsd.toFixed(2)}` : 'N/A';\nconst apAvailStr = (apifyPlanUsd !== null && apifyUsedUsd !== null)\n  ? `$${(apifyPlanUsd - apifyUsedUsd).toFixed(2)}`\n  : 'N/A';\n\n// 5. Timestamp & Message\nconst now = new Date().toLocaleString('en-IN', {\n  timeZone: 'Asia/Kolkata',\n  day: '2-digit', month: 'short', year: 'numeric',\n  hour: '2-digit', minute: '2-digit', hour12: true\n});\n\nconst message =\n`\ud83d\udcca <b>AI Tools \u2014 Daily Spend Report</b>\n\ud83d\udcc5 ${now}\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\ud83c\udfa8 <b>FAL AI</b>  <i>(Image Generation)</i>\n\u251c Balance Remaining: <b>${falStr}</b>\n\n\ud83e\udd16 <b>OpenRouter</b>  <i>(LLM / AI Models)</i>\n\u251c Total Balance: <b>${orBalanceStr}</b>\n\u2514 Credits Used: <b>${orUsedStr}</b>\n\n\ud83d\udd77 <b>Apify</b>  <i>(Web Scraping)</i>\n\u251c Monthly Plan: <b>${apPlanStr}</b>\n\u251c Used This Month: <b>${apUsedStr}</b>\n\u2514 Balance Available: <b>${apAvailStr}</b>\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\ud83d\udccb <a href=\"https://docs.google.com/spreadsheets/d/1NzUyg2REHooSmN2DqOWWUAnrrvuuBLyUq6jtb1KR5Zw/edit?gid=0#gid=0\">View Google Sheet</a>`;\n\nreturn [{ json: { message } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0e02b854-92bd-47f2-8f27-02149470f639",
      "name": "Send Telegram Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1760,
        208
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "chatId": "YOUR CHAT ID",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "27769036-8e0e-4604-bc97-bb68022515eb",
      "name": "When Scheduled at 10:30 & 20:02",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        608,
        208
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10,
              "triggerAtMinute": 30
            },
            {
              "triggerAtHour": 20,
              "triggerAtMinute": 2
            }
          ]
        }
      },
      "typeVersion": 1.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "f34b2455-ce0e-4b3c-8bd5-f123e3949d76",
  "nodeGroups": [],
  "connections": {
    "Fetch FAL AI Credits": {
      "main": [
        [
          {
            "node": "Fetch Open Router Credits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch APIFY Monthly Usage": {
      "main": [
        [
          {
            "node": "Collect Data in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Open Router Credits": {
      "main": [
        [
          {
            "node": "Fetch APIFY Monthly Usage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect Data in JavaScript": {
      "main": [
        [
          {
            "node": "Send Telegram Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Scheduled at 10:30 & 20:02": {
      "main": [
        [
          {
            "node": "Fetch FAL AI Credits",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}