{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "1492691c-98f1-46a3-8d27-3d7f067620dd",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        784,
        64
      ],
      "parameters": {
        "options": {
          "responseMode": "responseNodes"
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "16164596-fe99-4e3c-929a-414be89200da",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        784,
        576
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "chatInput"
            },
            {
              "name": "model"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "28dac69d-44a9-4c52-8a06-efafc48c3e8d",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        576
      ],
      "parameters": {
        "jsCode": "// Hole die Pricing-Daten vom Filter Node\nconst modelData = $('Filter').first().json;\nconst pricing = modelData.pricing;\n\n// Hole die Token-Usage vom LangChain Code Node\nconst tokenUsage = $json.tokenUsage;\n\n// Preise pro Token (von OpenRouter - sind bereits in Dollar pro Token)\nconst promptPrice = parseFloat(pricing.prompt);      // z.B. 0.0000004\nconst completionPrice = parseFloat(pricing.completion); // z.B. 0.0000016\n\n// Berechne Kosten\nconst inputCost = tokenUsage.input_tokens * promptPrice;\nconst outputCost = tokenUsage.output_tokens * completionPrice;\nconst totalCost = inputCost + outputCost;\n\nreturn {\n  // Original Output\n  output: $json.output,\n  \n  // Token Usage\n  tokenUsage: {\n    input_tokens: tokenUsage.input_tokens,\n    output_tokens: tokenUsage.output_tokens,\n    total_tokens: tokenUsage.total_tokens\n  },\n  \n  // Kosten in USD\n  costs: {\n    input_cost_usd: inputCost,\n    output_cost_usd: outputCost,\n    total_cost_usd: totalCost,\n    // Formatiert f\u00fcr bessere Lesbarkeit\n    total_cost_formatted: `$${totalCost.toFixed(8)}`\n  },\n  \n  // Model Info\n  model: {\n    id: modelData.id,\n    name: modelData.name,\n    prompt_price_per_token: promptPrice,\n    completion_price_per_token: completionPrice\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "8dc228d4-7dd0-4003-a444-4a36be89edb1",
      "name": "LangChain Code",
      "type": "@n8n/n8n-nodes-langchain.code",
      "position": [
        1680,
        576
      ],
      "parameters": {
        "code": {
          "execute": {
            "code": "const { PromptTemplate } = require('@langchain/core/prompts');\n\n// Get the LLM from ai_languageModel input\nconst llm = await this.getInputConnectionData('ai_languageModel', 0);\n\n// Get the chat input\nconst chatInput = $('When Executed by Another Workflow').first().json.chatInput;\n\n// Variable for token data\nlet tokenUsage = null;\n\n// Callback handler for token tracking\nconst tokenCallback = {\n  handleLLMEnd: async function(output, runId, parentId) {\n    try {\n      const generation = output.generations[0][0];\n      const message = generation.message;\n      if (message && message.usage_metadata) {\n        tokenUsage = {\n          input_tokens: message.usage_metadata.input_tokens,\n          output_tokens: message.usage_metadata.output_tokens,\n          total_tokens: message.usage_metadata.total_tokens\n        };\n      }\n    } catch (e) {\n      console.log('Token tracking error:', e);\n    }\n  }\n};\n\n// Create prompt and chain\nconst prompt = PromptTemplate.fromTemplate('{input}');\nconst chain = prompt.pipe(llm);\n\n// Invoke WITH callbacks (important: on invoke, not on the LLM!)\nconst response = await chain.invoke(\n  { input: chatInput },\n  { callbacks: [tokenCallback] }\n);\n\n// Return response with token data\nreturn [{\n  json: {\n    output: response.content,\n    tokenUsage: tokenUsage\n  }\n}];"
          }
        },
        "inputs": {
          "input": [
            {
              "type": "main",
              "required": true,
              "maxConnections": 1
            },
            {
              "type": "ai_languageModel",
              "required": true,
              "maxConnections": 1
            }
          ]
        },
        "outputs": {
          "output": [
            {
              "type": "main"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0365fe8b-f2ec-4144-b7e5-d09cb88cd193",
      "name": "Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        1456,
        576
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5e3a6f70-614e-4dda-bd44-f03d041dffba",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.id }}",
              "rightValue": "={{ $('When Executed by Another Workflow').item.json.model }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1e2846e8-2cd4-4b41-b208-5971b7c0dd56",
      "name": "Code in JavaScript1",
      "type": "n8n-nodes-base.code",
      "position": [
        1456,
        288
      ],
      "parameters": {
        "jsCode": "// Dropdown values must be { option: \"...\" } format (not name/value)\nconst dropdownValues = items\n  .map(item => ({\n    option: item.json.id,\n  }))\n  .sort((a, b) => a.option.localeCompare(b.option));\n\nconst formJson = [\n  {\n    fieldLabel: \"Select Model\",\n    fieldType: \"dropdown\",\n    fieldOptions: {\n      values: dropdownValues,\n    },\n    requiredField: true,\n  },\n  {\n    fieldLabel: \"Prompt\",\n    fieldType: \"textarea\",\n    placeholder: \"Enter your prompt/question\",\n    requiredField: true,\n  },\n];\n\n// Form Node expects a single item carrying the JSON\nreturn [{\n  json: {\n    formJson,\n    // Pass templates through for resolution after form submit\n    templates: items.map(i => i.json),\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ba0e8b3a-22ee-4054-873a-2884aacb3fc9",
      "name": "Form",
      "type": "n8n-nodes-base.form",
      "position": [
        1680,
        288
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n  --font-family: 'Inter', system-ui, -apple-system, sans-serif;\n  --font-weight-normal: 400;\n  --font-weight-bold: 600;\n  --font-size-body: 12px;\n  --font-size-label: 14px;\n  --font-size-input: 14px;\n  --font-size-header: 20px;\n  \n  /* Dark Theme Colors */\n  --color-background: #0f0f0f;\n  --color-card-bg: #1a1a1a;\n  --color-card-border: #2a2a2a;\n  --color-card-shadow: rgba(0, 0, 0, 0.4);\n  \n  --color-header: #e5e5e5;\n  --color-label: #888888;\n  --color-input-border: #2a2a2a;\n  --color-input-text: #e5e5e5;\n  --color-input-bg: #141414;\n  --color-focus-border: #2563eb;\n  \n  --color-submit-btn-bg: #2563eb;\n  --color-submit-btn-text: #ffffff;\n  --color-error: #ef4444;\n  --color-required: #ef4444;\n  \n  --color-html-text: #888888;\n  --color-html-link: #60a5fa;\n  --color-link: #888888;\n  \n  --border-radius-card: 12px;\n  --border-radius-input: 6px;\n  --box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n  --opacity-placeholder: 0.4;\n}\n\n/* Textarea & Select hover/focus */\ntextarea, select, input {\n  background: var(--color-input-bg) !important;\n  transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\ntextarea:hover, select:hover, input:hover {\n  border-color: #3a3a3a !important;\n}\n\ntextarea:focus, select:focus, input:focus {\n  border-color: var(--color-focus-border) !important;\n  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3) !important;\n  outline: none;\n}\n\n/* Select dropdown arrow */\nselect {\n  appearance: none;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888888' d='M6 8L1 3h10z'/%3E%3C/svg%3E\") !important;\n  background-repeat: no-repeat !important;\n  background-position: right 12px center !important;\n  padding-right: 36px !important;\n  cursor: pointer;\n}\n\n/* Submit Button hover */\nbutton[type=\"submit\"], .submit-btn {\n  transition: background-color 0.15s ease, transform 0.1s ease;\n}\n\nbutton[type=\"submit\"]:hover, .submit-btn:hover {\n  background: #3b82f6 !important;\n}\n\nbutton[type=\"submit\"]:active, .submit-btn:active {\n  transform: scale(0.98);\n}"
        },
        "defineForm": "json",
        "jsonOutput": "={{ $json.formJson }}"
      },
      "typeVersion": 2.3
    },
    {
      "id": "0158a19d-a67a-4723-84f0-90cf345e47e5",
      "name": "Form1",
      "type": "n8n-nodes-base.form",
      "position": [
        2128,
        288
      ],
      "parameters": {
        "operation": "completion",
        "respondWith": "showText",
        "responseText": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>AI Response Display</title>\n  <style>\n    * { margin: 0; padding: 0; box-sizing: border-box; }\n    body {\n      font-family: system-ui, -apple-system, sans-serif;\n      background: #0f0f0f;\n      color: #e5e5e5;\n      min-height: 100vh;\n      padding: 2rem;\n    }\n    .container { max-width: 600px; margin: 0 auto; }\n    .card {\n      background: #1a1a1a;\n      border: 1px solid #2a2a2a;\n      border-radius: 12px;\n      padding: 1.5rem;\n    }\n    .output {\n      font-size: 1rem;\n      line-height: 1.7;\n      padding-bottom: 1rem;\n      border-bottom: 1px solid #2a2a2a;\n      margin-bottom: 1rem;\n    }\n    \n    /* Markdown Styles */\n    .output h1 { font-size: 1.5rem; margin: 1.5rem 0 1rem; color: #fff; }\n    .output h2 { font-size: 1.25rem; margin: 1.25rem 0 0.75rem; color: #fff; }\n    .output h3 { font-size: 1.1rem; margin: 1rem 0 0.5rem; color: #fff; }\n    .output h4 { font-size: 1rem; margin: 1rem 0 0.5rem; color: #ddd; }\n    .output h1:first-child, .output h2:first-child, .output h3:first-child { margin-top: 0; }\n    \n    .output p { margin: 0.75rem 0; }\n    .output strong { color: #fff; font-weight: 600; }\n    \n    .output code {\n      background: #2a2a2a;\n      padding: 0.15rem 0.4rem;\n      border-radius: 4px;\n      font-family: 'SF Mono', Consolas, monospace;\n      font-size: 0.9em;\n      color: #f472b6;\n    }\n    \n    .output pre {\n      background: #141414;\n      border: 1px solid #2a2a2a;\n      border-radius: 8px;\n      padding: 1rem;\n      margin: 1rem 0;\n      overflow-x: auto;\n    }\n    .output pre code {\n      background: none;\n      padding: 0;\n      color: #e5e5e5;\n      font-size: 0.85rem;\n    }\n    \n    .output ul, .output ol {\n      margin: 0.75rem 0;\n      padding-left: 1.5rem;\n    }\n    .output li { margin: 0.35rem 0; }\n    \n    .output hr {\n      border: none;\n      border-top: 1px solid #2a2a2a;\n      margin: 1.5rem 0;\n    }\n    \n    .output a {\n      color: #60a5fa;\n      text-decoration: none;\n    }\n    .output a:hover { text-decoration: underline; }\n\n    /* Meta & Details */\n    .meta {\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      font-size: 0.875rem;\n      margin-bottom: 1rem;\n    }\n    .model {\n      background: #2563eb;\n      color: white;\n      padding: 0.25rem 0.75rem;\n      border-radius: 6px;\n      font-weight: 500;\n    }\n    .cost {\n      color: #22c55e;\n      font-family: monospace;\n      font-size: 0.9rem;\n    }\n    \n    details {\n      border-top: 1px solid #2a2a2a;\n      padding-top: 1rem;\n    }\n    summary {\n      cursor: pointer;\n      color: #888;\n      font-size: 0.8rem;\n      user-select: none;\n      display: flex;\n      align-items: center;\n      gap: 0.5rem;\n    }\n    summary:hover { color: #aaa; }\n    summary::marker { content: ''; }\n    summary .icon {\n      transition: transform 0.2s;\n      font-size: 0.7rem;\n    }\n    details[open] summary .icon {\n      transform: rotate(90deg);\n    }\n    \n    .details-grid {\n      display: grid;\n      grid-template-columns: 1fr 1fr;\n      gap: 1rem;\n      margin-top: 1rem;\n      padding: 1rem;\n      background: #141414;\n      border-radius: 8px;\n    }\n    .detail-section h4 {\n      color: #666;\n      font-size: 0.7rem;\n      text-transform: uppercase;\n      letter-spacing: 0.05em;\n      margin-bottom: 0.5rem;\n    }\n    .detail-row {\n      display: flex;\n      justify-content: space-between;\n      font-size: 0.8rem;\n      padding: 0.25rem 0;\n    }\n    .detail-row .label { color: #888; }\n    .detail-row .value { \n      font-family: monospace;\n      color: #e5e5e5;\n    }\n    .detail-row .value.green { color: #22c55e; }\n    .detail-row .value.blue { color: #60a5fa; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"card\">\n      <div class=\"output\">{{ $json.output }}</div>\n      \n      <div class=\"meta\">\n        <span class=\"model\">{{ $json.model.id }}</span>\n        <span class=\"cost\">{{ $json.costs.total_cost_formatted }}</span>\n      </div>\n      \n      <details>\n        <summary><span class=\"icon\">\u25b6</span>Show details</summary>\n        <div class=\"details-grid\">\n          <div class=\"detail-section\">\n            <h4>Token Usage</h4>\n            <div class=\"detail-row\">\n              <span class=\"label\">Input</span>\n              <span class=\"value\">{{ $json.tokenUsage.input_tokens }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Output</span>\n              <span class=\"value\">{{ $json.tokenUsage.output_tokens }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Total</span>\n              <span class=\"value blue\">{{ $json.tokenUsage.total_tokens }}</span>\n            </div>\n          </div>\n          \n          <div class=\"detail-section\">\n            <h4>Costs</h4>\n            <div class=\"detail-row\">\n              <span class=\"label\">Input</span>\n              <span class=\"value\">${{ $json.costs.input_cost_usd }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Output</span>\n              <span class=\"value\">${{ $json.costs.output_cost_usd }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Total</span>\n              <span class=\"value green\">${{ $json.costs.total_cost_usd }}</span>\n            </div>\n          </div>\n          \n          <div class=\"detail-section\" style=\"grid-column: span 2;\">\n            <h4>Model Pricing</h4>\n            <div class=\"detail-row\">\n              <span class=\"label\">Prompt (per token)</span>\n              <span class=\"value\">${{ $json.model.prompt_price_per_token }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Completion (per token)</span>\n              <span class=\"value\">${{ $json.model.completion_price_per_token }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Model Name</span>\n              <span class=\"value\">{{ $json.model.name }}</span>\n            </div>\n          </div>\n        </div>\n      </details>\n    </div>\n  </div>\n</body>\n</html>"
      },
      "typeVersion": 2.3
    },
    {
      "id": "8e0635fb-e651-4848-8491-07b8c0c58ed8",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1232,
        288
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "3de0f267-dc22-4807-a9ef-32812e8f5ecd",
      "name": "Split Out1",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1232,
        576
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "ea0a8895-e1e3-4897-8198-2348e4deb84a",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        0
      ],
      "parameters": {
        "width": 688,
        "height": 224,
        "content": "## Chat (simple testing via chat)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1615dd6e-0c15-46cc-872c-9d9cea8cbb9b",
      "name": "Respond to Chat",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        1232,
        64
      ],
      "parameters": {
        "message": "={{ $json.output }}\n\n---\n\n**{{ $json.model.id }}** \u00b7 `{{ $json.costs.total_cost_formatted }}`\n\n**Tokens** \u00b7 Input: {{ $json.tokenUsage.input_tokens }} \u00b7 Output: {{ $json.tokenUsage.output_tokens }} \u00b7 Total: **{{ $json.tokenUsage.total_tokens }}**\n\n**Costs** \u00b7 Input: ${{ $json.costs.input_cost_usd.toFixed(7) }} \u00b7 Output: ${{ $json.costs.output_cost_usd.toFixed(7) }} \u00b7 Total: **{{ $json.costs.total_cost_formatted }}**\n\n*{{ $json.model.name }} \u00b7 Prompt ${{ $json.model.prompt_price_per_token.toFixed(7) }}/tk \u00b7 Completion ${{ $json.model.completion_price_per_token.toFixed(7) }}/tk*",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "b4cd2c9f-18fd-4ae0-9569-cf68e351fd80",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        240
      ],
      "parameters": {
        "color": 7,
        "width": 1648,
        "height": 240,
        "content": "## UI\n"
      },
      "typeVersion": 1
    },
    {
      "id": "de85ae21-918d-48d4-8e29-62fc275bbc83",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        784,
        288
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n  --font-family: 'Inter', system-ui, -apple-system, sans-serif;\n  --font-weight-normal: 400;\n  --font-weight-bold: 600;\n  --font-size-body: 12px;\n  --font-size-label: 14px;\n  --font-size-input: 14px;\n  --font-size-header: 20px;\n  \n  /* Dark Theme Colors */\n  --color-background: #0f0f0f;\n  --color-card-bg: #1a1a1a;\n  --color-card-border: #2a2a2a;\n  --color-card-shadow: rgba(0, 0, 0, 0.4);\n  \n  --color-header: #e5e5e5;\n  --color-label: #888888;\n  --color-input-border: #2a2a2a;\n  --color-input-text: #e5e5e5;\n  --color-input-bg: #141414;\n  --color-focus-border: #2563eb;\n  \n  --color-submit-btn-bg: #2563eb;\n  --color-submit-btn-text: #ffffff;\n  --color-error: #ef4444;\n  --color-required: #ef4444;\n  \n  --color-html-text: #888888;\n  --color-html-link: #60a5fa;\n  --color-link: #888888;\n  \n  --border-radius-card: 12px;\n  --border-radius-input: 6px;\n  --box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n  --opacity-placeholder: 0.4;\n}\n\n/* Textarea & Select hover/focus */\ntextarea, select, input {\n  background: var(--color-input-bg) !important;\n  transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\ntextarea:hover, select:hover, input:hover {\n  border-color: #3a3a3a !important;\n}\n\ntextarea:focus, select:focus, input:focus {\n  border-color: var(--color-focus-border) !important;\n  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3) !important;\n  outline: none;\n}\n\n/* Select dropdown arrow */\nselect {\n  appearance: none;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888888' d='M6 8L1 3h10z'/%3E%3C/svg%3E\") !important;\n  background-repeat: no-repeat !important;\n  background-position: right 12px center !important;\n  padding-right: 36px !important;\n  cursor: pointer;\n}\n\n/* Submit Button hover */\nbutton[type=\"submit\"], .submit-btn {\n  transition: background-color 0.15s ease, transform 0.1s ease;\n}\n\nbutton[type=\"submit\"]:hover, .submit-btn:hover {\n  background: #3b82f6 !important;\n}\n\nbutton[type=\"submit\"]:active, .submit-btn:active {\n  transform: scale(0.98);\n}",
          "buttonLabel": "Start"
        },
        "formTitle": "LLM Token Cost Tracker",
        "formDescription": "\ud83d\udd0d Find out exactly what your AI requests cost.\n\n  This tool lets you:\n  \u2022 Choose from 350+ LLM models (GPT-4, Claude, Llama, etc.)\n  \u2022 Enter any prompt and run it\n  \u2022 See the exact token usage and cost breakdown\n\n  Perfect for comparing model prices or tracking your AI spending"
      },
      "typeVersion": 2.3
    },
    {
      "id": "c70b764d-65eb-41bd-81a7-61c20a983239",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        496
      ],
      "parameters": {
        "color": 6,
        "width": 1536,
        "height": 336,
        "content": "## Backend\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a305499a-09d9-4636-bd66-9f0fdd9e230a",
      "name": "OpenRouter",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1680,
        720
      ],
      "parameters": {
        "model": "={{ $('When Executed by Another Workflow').item.json.model }}",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5119d08c-5d14-43e1-b89c-010cb11abc30",
      "name": "Backend",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        1904,
        288
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}",
          "cachedResultUrl": "/workflow/=%7B%7B%20$workflow.id%20%7D%7D"
        },
        "workflowInputs": {
          "value": {
            "model": "={{ $json[\"Select Model\"] }}",
            "chatInput": "={{ $json.Prompt }}"
          },
          "schema": [
            {
              "id": "chatInput",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "chatInput",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "model",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "17649aeb-5fe6-4ef6-89b6-797b6a98d5a7",
      "name": "Backend1",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        1008,
        64
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}",
          "cachedResultUrl": "/workflow/=%7B%7B%20$workflow.id%20%7D%7D"
        },
        "workflowInputs": {
          "value": {
            "model": "openai/gpt-4.1-mini",
            "chatInput": "={{ $json.chatInput }}"
          },
          "schema": [
            {
              "id": "chatInput",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "chatInput",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "model",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1a982773-b900-45cf-9bb9-6a6cccef8c2c",
      "name": "Get Openrouter models",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1008,
        288
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/models",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "3816f346-0b0b-40cf-9c15-63a1851b34b7",
      "name": "Get Openrouter models1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1008,
        576
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/models",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ddde7547-c651-43a5-b58f-d67bde3e8839",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 4,
        "width": 704,
        "height": 1600,
        "content": "# LLM Token Cost Tracker\n  \ud83d\udd0d **Find out exactly what your AI requests cost.**\n  ---\n  ## \u2728 Features\n  - **350+ Models** - Access GPT-4, Claude, Llama, Mistral, and many more\n  - **Real-time Pricing** - Costs calculated using live OpenRouter pricing data\n  - **Detailed Breakdown** - See input tokens, output tokens, and cost per category\n  - **Two Interfaces** - Use via Chat or interactive Form\n  ---\n  ## \ud83d\udee0\ufe0f Setup\n  ### 1. Get your OpenRouter API Key\n  1. Visit [OpenRouter API Keys](https://openrouter.ai/settings/keys)\n  2. Click **\"Create Key\"**\n  3. Copy your new API key\n\n  ### 2. Configure the HTTP Node\n  1. Open the **HTTP Request** node (fetches model list)\n  2. In the **Authentication** dropdown, select **\"Bearer YOUR_TOKEN_HERE\"**\n  3. Click **\"Create New Credential\"**\n  4. Paste your API key and save\n\n  ### 3. Configure the OpenRouter Chat Model\n  1. Open the **OpenRouter Chat Model** node (attached to the LangChain Code node)\n  2. Click **\"Create New Credential\"**\n  3. Paste the same API key and save\n\n  \u2705 **Done!** Your workflow is ready to use.\n  ---\n\n  ## \ud83d\ude80 Usage\n  ### Option 1: Chat Interface\n  The quickest way to test:\n\n  1. Open the **Chat** panel in n8n\n  2. Type any prompt\n  3. Get your response + cost breakdown directly in the chat\n\n  ### Option 2: Form Interface\n  For model selection and detailed results:\n\n  1. Click **\"Form Submission\"** \u2192 **\"Start\"**\n  2. Wait a moment while all available models are fetched from OpenRouter\n  3. **Select a model** from the dropdown (e.g., `openai/gpt-4.1-mini`)\n  4. **Enter your prompt** in the textarea\n  5. Click **\"Submit\"**\n  6. View the **result form** with:\n     - The AI response\n     - Total cost\n     - Click **\"Show Details\"** for full breakdown:\n       - Input tokens\n       - Output tokens\n       - Cost per token type\n       - Model pricing info\n\n  ---\n  ## \ud83d\udca1 Use Cases\n  - **Compare model costs** - Same prompt, different models, see price differences\n  - **Budget planning** - Estimate costs before scaling up\n  - **Optimize prompts** - See how prompt length affects cost\n  - **Client billing** - Track exact costs per request\n  ---\n  ## \ud83d\udd17 Links\n  - [OpenRouter](https://openrouter.ai/) - Multi-model API gateway\n  - [OpenRouter Pricing](https://openrouter.ai/models) - Current model prices\n  - [Get API Key](https://openrouter.ai/settings/keys) - Create your key here\n\n  ---\n  Made with \u2764\ufe0f by philflow for the n8n community\n  ---"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Form": {
      "main": [
        [
          {
            "node": "Backend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        [
          {
            "node": "LangChain Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Backend": {
      "main": [
        [
          {
            "node": "Form1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Backend1": {
      "main": [
        [
          {
            "node": "Respond to Chat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter": {
      "ai_languageModel": [
        [
          {
            "node": "LangChain Code",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Split Out1": {
      "main": [
        [
          {
            "node": "Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LangChain Code": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Get Openrouter models",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "Form",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Openrouter models": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Openrouter models1": {
      "main": [
        [
          {
            "node": "Split Out1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Backend1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Get Openrouter models1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}