AutomationFlowsWeb Scraping › Bailian Multi-account Billing Alert (fixed Chart Flow)

Bailian Multi-account Billing Alert (fixed Chart Flow)

Bailian Multi-Account Billing Alert (Fixed Chart Flow). Uses httpRequest, errorTrigger. Scheduled trigger; 17 nodes.

Cron / scheduled trigger★★★★☆ complexity17 nodesHTTP RequestError Trigger
Web Scraping Trigger: Cron / scheduled Nodes: 17 Complexity: ★★★★☆ Added:

This workflow follows the Error Trigger → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Bailian Multi-Account Billing Alert (Fixed Chart Flow)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 17
            }
          ]
        }
      },
      "id": "schedule",
      "name": "Daily 17:00 Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6\u5f53\u524d\u5317\u4eac\u65f6\u95f4(UTC+8)\nconst now = new Date();\nconst utcOffset = now.getTimezoneOffset() * 60000; // \u672c\u5730\u65f6\u533a\u504f\u79fb(\u6beb\u79d2)\nconst utc = now.getTime() + utcOffset; // UTC\u65f6\u95f4\nconst beijingTime = new Date(utc + (8 * 60 * 60 * 1000)); // \u5317\u4eac\u65f6\u95f4 UTC+8\n\n// \u8ba1\u7b97\u4eca\u5929 17:00 \u5317\u4eac\u65f6\u95f4\nconst today17 = new Date(beijingTime);\ntoday17.setHours(17, 0, 0, 0);\n\n// \u5982\u679c\u5f53\u524d\u5317\u4eac\u65f6\u95f4\u5c0f\u4e8e\u4eca\u592917\u70b9,\u4f7f\u7528\u6628\u592917\u70b9\u4f5c\u4e3a\u7ed3\u675f\u65f6\u95f4\nconst endTime = beijingTime.getTime() < today17.getTime() \n  ? new Date(today17.getTime() - 24 * 60 * 60 * 1000)\n  : today17;\n\n// \u5f00\u59cb\u65f6\u95f4\u662f\u7ed3\u675f\u65f6\u95f4\u524d24\u5c0f\u65f6\nconst startTime = new Date(endTime.getTime() - 24 * 60 * 60 * 1000);\n\n// \u683c\u5f0f\u5316\u4e3a\u5317\u4eac\u65f6\u95f4\u663e\u793a\nconst formatDate = (date) => {\n  const pad = (n) => String(n).padStart(2, '0');\n  const month = pad(date.getMonth() + 1);\n  const day = pad(date.getDate());\n  const hour = pad(date.getHours());\n  const minute = pad(date.getMinutes());\n  return `${month}-${day} ${hour}:${minute}`;\n};\n\nreturn {\n  startISO: startTime.toISOString(),\n  endISO: endTime.toISOString(),\n  startTs: Math.floor(startTime.getTime() / 1000),\n  endTs: Math.floor(endTime.getTime() / 1000),\n  windowLabel: `${formatDate(startTime)} ~ ${formatDate(endTime)}`\n};"
      },
      "id": "calc-window",
      "name": "Calc Window",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const windowCtx = $input.first().json;\nconst accounts = [\n  { cookie: $env.BILLING_COOKIE, accountLabel: '\u4e3b\u8d26\u53f7' },\n  { cookie: $env.BILLING_COOKIE_SECOND, accountLabel: '\u5907\u7528\u8d26\u53f7' }\n].filter((entry) => entry.cookie && entry.cookie.trim());\n\nif (!accounts.length) {\n  throw new Error('\u81f3\u5c11\u9700\u8981\u914d\u7f6e\u4e00\u4e2a BILLING_COOKIE');\n}\n\nreturn accounts.map((entry, index) => ({\n  json: {\n    ...windowCtx,\n    cookie: entry.cookie,\n    accountLabel: entry.accountLabel || `\u8d26\u53f7${index + 1}`\n  }\n}));"
      },
      "id": "prepare-accounts",
      "name": "Prepare Accounts",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "url": "=https://bailian.dev/api/uptime/status?start={{ $json.startTs }}&end={{ $json.endTs }}",
        "bodyParameters": {
          "parameters": []
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Cookie",
              "value": "={{ $json.cookie }}"
            }
          ]
        },
        "queryParameters": {
          "parameters": []
        },
        "options": {
          "timeout": 30000
        }
      },
      "id": "fetch-billing",
      "name": "Fetch Billing Data",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        700,
        200
      ]
    },
    {
      "parameters": {
        "mode": "multiplex"
      },
      "id": "merge-context",
      "name": "Merge Context",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 2.1,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// \u5904\u7406\u6240\u6709\u8f93\u5165\u9879(\u6bcf\u4e2a\u8d26\u53f7\u4e00\u4e2a\u9879)\nconst allItems = $input.all();\nconst results = [];\n\nfor (let i = 0; i < allItems.length; i++) {\n  const payload = allItems[i].json;\n  \n  // \u5982\u679c\u5df2\u7ecf\u6709 accountLabel,\u8bf4\u660e\u5df2\u7ecf\u662f\u5904\u7406\u540e\u7684\u6570\u636e\n  if (payload.accountLabel && payload.totalAmount !== undefined) {\n    results.push({ json: payload });\n    continue;\n  }\n  \n  // \u4eceAPI\u54cd\u5e94\u4e2d\u63d0\u53d6\u6570\u636e\n  const api = payload.data || payload.stats || payload.summary || payload;\n  const stats = api.summary || api.stats || api;\n  \n  const num = (value) => {\n    if (value === undefined || value === null || value === '') return 0;\n    const parsed = Number(value);\n    return Number.isNaN(parsed) ? 0 : parsed;\n  };\n  \n  const totalAmount = num(stats.totalAmount || stats.amount || stats.consume || stats.total || api.totalAmount);\n  const requestCount = Math.round(num(stats.requestCount || stats.requests || stats.totalRequests || api.requestCount));\n  const balance = num(payload.balance || (payload.account && payload.account.balance) || api.balance);\n  \n  results.push({\n    json: {\n      accountLabel: payload.accountLabel || '\u8d26\u53f7',\n      startISO: payload.startISO,\n      endISO: payload.endISO,\n      windowLabel: payload.windowLabel,\n      totalAmount: Number(totalAmount.toFixed(2)),\n      requestCount: requestCount,\n      balance: Number(balance.toFixed(2))\n    }\n  });\n}\n\nreturn results;"
      },
      "id": "extract-metrics",
      "name": "Extract Metrics",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        300
      ]
    },
    {
      "id": "prepare-chart-url",
      "name": "Prepare Chart URL",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1300,
        300
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\n// 1. \u51c6\u5907\u56fe\u8868\u6570\u636e\n// \u8fc7\u6ee4\u6389\u6ca1\u6709\u6d88\u8017\u7684\u8d26\u6237\uff0c\u907f\u514d\u751f\u6210\u7a7a\u56fe\u8868\nconst activeItems = items.filter(item => item.json.totalAmount > 0);\nconst labels = activeItems.map(item => item.json.accountLabel);\nconst data = activeItems.map(item => item.json.totalAmount);\n\nlet chartUrl = null;\n// 2. \u6784\u5efa\u56fe\u8868 URL (\u4f7f\u7528 QuickChart.io)\n// \u53ea\u6709\u5f53\u6709\u6709\u6548\u6570\u636e\u65f6\u624d\u751f\u6210 URL\nif (labels.length > 0) {\n    // \u5b9a\u4e49\u56fe\u8868\u914d\u7f6e\n    const chartConfig = {\n        type: 'bar', // \u4f7f\u7528\u67f1\u72b6\u56fe\uff0c\u5bf9\u6bd4\u66f4\u6e05\u6670\n        data: {\n            labels: labels,\n            datasets: [{\n                label: '\u4eca\u65e5\u6d88\u8017 (\u00a5)',\n                data: data,\n                // \u8bbe\u7f6e\u597d\u770b\u7684\u84dd\u8272\u67f1\u5b50\n                backgroundColor: 'rgba(54, 162, 235, 0.6)',\n                borderColor: 'rgba(54, 162, 235, 1)',\n                borderWidth: 1\n            }]\n        },\n        options: {\n            scales: {\n                yAxes: [{\n                    ticks: {\n                        beginAtZero: true // Y\u8f74\u4ece0\u5f00\u59cb\n                    }\n                }]\n            },\n            legend: {\n                display: false // \u9690\u85cf\u56fe\u4f8b\n            },\n            title: {\n                display: true,\n                text: '\u5404\u8d26\u6237\u4eca\u65e5\u6d88\u8017\u5bf9\u6bd4' // \u56fe\u8868\u6807\u9898\n            }\n        }\n    };\n    // \u5bf9\u914d\u7f6e\u8fdb\u884c URL \u7f16\u7801\n    const encodedConfig = encodeURIComponent(JSON.stringify(chartConfig));\n    // \u751f\u6210\u5b8c\u6574 URL\uff0c\u8bbe\u7f6e\u80cc\u666f\u4e3a\u767d\u8272\n    chartUrl = `https://quickchart.io/chart?w=500&h=300&bkg=white&c=${encodedConfig}`;\n}\n\n// 3. \u5c06\u539f\u59cb\u6570\u636e\u548c\u751f\u6210\u7684URL\u4e00\u8d77\u5411\u4e0b\u4f20\u9012\n// \u6211\u4eec\u9700\u8981\u4fdd\u7559\u6240\u6709items\u4ee5\u4fbf\u540e\u7eed\u8ba1\u7b97\u603b\u548c\nreturn items.map(item => ({\n    json: {\n        ...item.json,\n        chartUrl: chartUrl // \u5982\u679c\u6ca1\u6709\u6570\u636e\uff0c\u8fd9\u91cc\u4f1a\u662f null\n    }\n}));"
      }
    },
    {
      "id": "get-feishu-token",
      "name": "Get Feishu Token",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1680,
        180
      ],
      "parameters": {
        "method": "POST",
        "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "app_id",
              "value": "cli_a8438dfffcfc500d"
            },
            {
              "name": "app_secret",
              "value": "d209kVm3YntIQOj3Kr7qnh2NrCF7i67s"
            }
          ]
        },
        "headerParameters": {
          "parameters": []
        },
        "queryParameters": {
          "parameters": []
        },
        "options": {}
      }
    },
    {
      "id": "download-chart-image",
      "name": "Download Chart Image",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1680,
        380
      ],
      "parameters": {
        "url": "={{ $json.chartUrl }}",
        "bodyParameters": {
          "parameters": []
        },
        "headerParameters": {
          "parameters": []
        },
        "queryParameters": {
          "parameters": []
        },
        "options": {
          "responseFormat": "file",
          "binaryPropertyName": "chartImage"
        }
      }
    },
    {
      "id": "upload-image-to-feishu",
      "name": "Upload Image to Feishu",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1880,
        280
      ],
      "parameters": {
        "method": "POST",
        "url": "https://open.feishu.cn/open-apis/im/v1/images",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $('Get Feishu Token').item.json.tenant_access_token }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "image_type",
              "value": "message"
            }
          ]
        },
        "queryParameters": {
          "parameters": []
        },
        "sendBinaryData": true,
        "binaryPropertyName": "chartImage:image",
        "options": {}
      }
    },
    {
      "id": "build-final-card",
      "name": "Build Final Card",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2300,
        300
      ],
      "parameters": {
        "jsCode": "// 1. \u83b7\u53d6\u539f\u59cb\u6570\u636e (\u59cb\u7ec8\u6765\u81ea Prepare Chart URL \u8282\u70b9)\nconst inputItems = $('Prepare Chart URL').all();\n\n// 2. \u83b7\u53d6\u5f53\u524d\u8282\u70b9\u7684\u8f93\u5165\uff0c\u8fd9\u53ef\u80fd\u662f\u4e0a\u4f20\u7ed3\u679c\uff0c\u4e5f\u53ef\u80fd\u662f\u4ece IF \u8282\u70b9\u76f4\u63a5\u8fc7\u6765\u7684\u539f\u59cb\u6570\u636e\nconst mergeResult = $input.first().json;\n\n// 3. \u5c1d\u8bd5\u63d0\u53d6 img_key\nlet imgKey = null;\nif (mergeResult && mergeResult.data && mergeResult.data.image_key) {\n    // \u8bf4\u660e\u662f\u4e0a\u4f20\u6210\u529f\u540e\u7684\u7ed3\u679c\n    imgKey = mergeResult.data.image_key;\n}\n\n// \u5982\u679c\u6ca1\u6709\u8f93\u5165\u6570\u636e\uff0c\u8fd4\u56de\u5f02\u5e38\u5361\u7247\nif (!inputItems.length) {\n  return {\n    msg_type: 'interactive',\n    card: {\n      header: { title: { tag: 'plain_text', content: '\u26a0\ufe0f \u8d26\u5355\u6570\u636e\u5f02\u5e38' }, template: 'orange' },\n      elements: [{ tag: 'div', text: { tag: 'plain_text', content: '\u672a\u83b7\u53d6\u5230\u4efb\u4f55\u6709\u6548\u8d26\u6237\u6570\u636e\u3002' } }] }\n  };\n}\n\n// --- \u65f6\u95f4\u5904\u7406 ---\n// \u683c\u5f0f\u5316 ISO \u65f6\u95f4\u4e3a\u4e2d\u56fd\u6807\u51c6\u65f6\u95f4\u5b57\u7b26\u4e32\nconst formatCST = (iso) => {\n  if (!iso) return 'N/A';\n  return new Date(iso).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai', hour12: false });\n};\n\n// \u83b7\u53d6\u65f6\u95f4\u533a\u95f4\u7684\u5f00\u59cb\u548c\u7ed3\u675f\u6807\u7b7e\nconst startLabel = formatCST(inputItems[0].json.startISO);\nconst endLabel = formatCST(inputItems[0].json.endISO);\n\n// --- \u6570\u636e\u6c47\u603b ---\n// \u5c06\u6240\u6709\u8f93\u5165\u9879\u6620\u5c04\u4e3a\u7edf\u4e00\u7684\u884c\u6570\u636e\u7ed3\u6784\nconst rows = inputItems.map(({ json }) => ({\n  label: json.accountLabel || '\u8d26\u53f7',\n  total: Number(json.totalAmount) || 0,\n  requests: Number(json.requestCount) || 0,\n  balance: Number(json.balance) || 0\n}));\n\n// \u8ba1\u7b97\u6240\u6709\u8d26\u6237\u7684\u603b\u548c\nconst totals = rows.reduce((acc, row) => ({\n  total: acc.total + row.total,\n  requests: acc.requests + row.requests,\n  balance: acc.balance + row.balance\n}), { total: 0, requests: 0, balance: 0 });\n\n// --- \u6784\u5efa\u5361\u7247\u5143\u7d20 ---\nconst elements = [];\n\n// 1. \u9876\u90e8\u65f6\u95f4\u548c\u6c47\u603b\u533a\u57df\nelements.push(\n  { tag: 'div', text: { tag: 'lark_md', content: `**\u65f6\u95f4\u533a\u95f4**\\\\n${startLabel} ~ ${endLabel}` } },\n  { tag: 'hr' },\n  {\n    tag: 'div',\n    fields: [\n      { is_short: true, text: { tag: 'lark_md', content: `**\u6c47\u603b\u6d88\u8017**\\\\n\u00a5${totals.total.toFixed(2)}` } },\n      { is_short: true, text: { tag: 'lark_md', content: `**\u603b\u8bf7\u6c42\u6570**\\\\n${totals.requests.toLocaleString('zh-CN')}` } },\n      { is_short: true, text: { tag: 'lark_md', content: `**\u603b\u4f59\u989d**\\\\n\u00a5${totals.balance.toFixed(2)}` } }\n    ]\n  }\n);\n\n// 2. \u63d2\u5165\u56fe\u8868\u533a\u57df (\u5173\u952e\u70b9\uff1a\u4f7f\u7528 img_key)\n// \u53ea\u6709\u5f53\u6210\u529f\u83b7\u53d6\u5230 imgKey \u65f6\u624d\u6dfb\u52a0\u56fe\u8868\u6a21\u5757\nif (imgKey) {\n    elements.push(\n        { tag: 'hr' },\n        {\n            tag: 'img',\n            img_key: imgKey,\n            alt: { tag: 'plain_text', content: '\u4eca\u65e5\u6d88\u8017\u5bf9\u6bd4\u56fe' },\n            mode: 'fit_horizontal',\n            preview: true\n        }\n    );\n}\n\n// 3. \u5404\u8d26\u6237\u8be6\u60c5\u533a\u57df\n// \u4e3a\u6bcf\u4e2a\u8d26\u6237\u6784\u5efa\u4e00\u4e2a\u5b57\u6bb5\u5bf9\u8c61\nconst accountFields = rows.map((row) => ({\n  is_short: true,\n  text: { tag: 'lark_md', content: `**${row.label}**\\\\n\ud83d\udcb0 \u00a5${row.total.toFixed(2)} | \ud83d\udd22 ${row.requests.toLocaleString('zh-CN')} | \ud83d\udcb3 \u00a5${row.balance.toFixed(2)}` }\n}));\n\n// \u5c06\u6240\u6709\u8d26\u6237\u5b57\u6bb5\u6dfb\u52a0\u5230\u4e00\u4e2a div \u5bb9\u5668\u4e2d\nelements.push(\n    { tag: 'hr' },\n    { tag: 'div', fields: accountFields }\n);\n\n// --- \u8fd4\u56de\u6700\u7ec8\u5361\u7247\u7ed3\u6784 ---\nreturn {\n  msg_type: 'interactive',\n  card: {\n    config: { wide_screen_mode: true },\n    header: { title: { tag: 'plain_text', content: '\ud83d\udcca \u767e\u94fe\u8d26\u5355\u65e5\u5ea6\u64ad\u62a5' }, template: 'turquoise' },\n    elements: elements\n  }\n};\n"
      }
    },
    {
      "id": "send-final-alert",
      "name": "Send Feishu Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2500,
        300
      ],
      "parameters": {
        "method": "POST",
        "url": "={{ $env.FEISHU_WEBHOOK }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($input.first().json) }}",
        "bodyParameters": {
          "parameters": []
        },
        "headerParameters": {
          "parameters": []
        },
        "queryParameters": {
          "parameters": []
        },
        "options": {
          "timeout": 15000
        }
      }
    },
    {
      "parameters": {},
      "id": "f1e2d3c4-b5a6-4789-8b7c-6d5e4f3a2b1c",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "typeVersion": 1,
      "position": [
        -650,
        -80
      ]
    },
    {
      "parameters": {
        "jsCode": "const detail = $input.first().json;\nconst message = detail.error?.message ?? '\u672a\u77e5\u9519\u8bef';\nconst node = detail.error?.node?.name ?? '\u672a\u6355\u83b7\u8282\u70b9';\nconst timestamp = new Date().toLocaleString('zh-CN', { hour12: false, timeZone: 'Asia/Shanghai' });\n\nreturn {\n  msg_type: 'interactive',\n  card: {\n    config: { wide_screen_mode: true },\n    header: { \n      title: { tag: 'plain_text', content: '\u274c \u767e\u94fe\u8d26\u5355\u6293\u53d6\u5931\u8d25' }, \n      template: 'red' \n    },\n    elements: [\n      { tag: 'div', text: { tag: 'lark_md', content: `**\u5931\u8d25\u8282\u70b9**\\n${node}` } },\n      { tag: 'div', text: { tag: 'lark_md', content: `**\u9519\u8bef\u4fe1\u606f**\\n${message}` } },\n      { tag: 'div', text: { tag: 'lark_md', content: `**\u53d1\u751f\u65f6\u95f4**\\n${timestamp}` } }\n    ]\n  }\n};"
      },
      "id": "0a1b2c3d-4e5f-6789-8a7b-6c5d4e3f2a1b",
      "name": "Build Failure Card",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -400,
        -80
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.FEISHU_WEBHOOK }}",
        "authentication": "none",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json) }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "bodyParameters": {
          "parameters": []
        },
        "queryParameters": {
          "parameters": []
        },
        "options": {
          "timeout": 15000
        }
      },
      "id": "1b2c3d4e-5f6a-789b-8c7d-6e5f4d3c2b1d",
      "name": "Send Failure Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -150,
        -80
      ]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.chartUrl }}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "id": "if-chart-url-exists",
      "name": "IF: Chart URL Exists?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1500,
        300
      ]
    },
    {
      "parameters": {},
      "id": "merge-flow",
      "name": "Merge Flow",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 2.1,
      "position": [
        2100,
        300
      ]
    }
  ],
  "connections": {
    "Daily 17:00 Trigger": {
      "main": [
        [
          {
            "node": "Calc Window",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calc Window": {
      "main": [
        [
          {
            "node": "Prepare Accounts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Accounts": {
      "main": [
        [
          {
            "node": "Fetch Billing Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Context",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Fetch Billing Data": {
      "main": [
        [
          {
            "node": "Merge Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Context": {
      "main": [
        [
          {
            "node": "Extract Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Metrics": {
      "main": [
        [
          {
            "node": "Prepare Chart URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Chart URL": {
      "main": [
        [
          {
            "node": "IF: Chart URL Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Feishu Token": {
      "main": [
        [
          {
            "node": "Upload Image to Feishu",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Chart Image": {
      "main": [
        [
          {
            "node": "Upload Image to Feishu",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Upload Image to Feishu": {
      "main": [
        [
          {
            "node": "Merge Flow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Final Card": {
      "main": [
        [
          {
            "node": "Send Feishu Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Build Failure Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Failure Card": {
      "main": [
        [
          {
            "node": "Send Failure Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Chart URL Exists?": {
      "main": [
        [
          {
            "node": "Get Feishu Token",
            "type": "main",
            "index": 0
          },
          {
            "node": "Download Chart Image",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge Flow",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Flow": {
      "main": [
        [
          {
            "node": "Build Final Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "staticData": null,
  "tags": [],
  "triggerCount": 0,
  "versionId": "3"
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Bailian Multi-Account Billing Alert (Fixed Chart Flow). Uses httpRequest, errorTrigger. Scheduled trigger; 17 nodes.

Source: https://github.com/N1rvana-git/channel-getstat/blob/9743d52dc8fb98b0210f9b3411ec09d167aeaaca/workflows/final_nodes.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

PRIMA - Automatisation Prospection Sophie (nettoyé). Uses httpRequest, errorTrigger, emailSend. Scheduled trigger; 20 nodes.

HTTP Request, Error Trigger, Email Send
Web Scraping

WB-07: SLA Breach Escalation (Every 2h). Uses httpRequest, errorTrigger. Scheduled trigger; 8 nodes.

HTTP Request, Error Trigger
Web Scraping

WB-08: Daily Report (9 AM IST). Uses httpRequest, errorTrigger. Scheduled trigger; 8 nodes.

HTTP Request, Error Trigger
Web Scraping

n8n_Heartbeat. Uses httpRequest, errorTrigger. Scheduled trigger; 5 nodes.

HTTP Request, Error Trigger
Web Scraping

Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.

Stop And Error, HTTP Request, Email Send +1