Exaba pricing engine v0.1.0

Exaba Pricing Engine

Human page at /. Callable endpoints stay under /api/.... This page shows the setup assumptions, curl examples, a generated 48-month spreadsheet, a JSON report link, and a button that fetches the JavaScript engine from /api/..., evaluates it in the page, and renders the report with getValue(attribute, month). It also includes Plotly.js, D3.js, and Chart.js graph demos driven by the same report rows.

Setup assumption presets

Download Demo Spreadsheet Open Demo JSON Report Open JavaScript Engine

Setup Assumptions

Changing the scenario buttons updates these assumptions and the demo links above.

{
  "scenarioName": "Exaba Demo Scenario 1",
  "months": 48,
  "startingTB": 2000.0,
  "monthlyGrowthTB": 80.0,
  "revenuePerTBPerMonth": 20.0,
  "costPerTBPerMonth": 2.0,
  "currency": "USD",
  "pricingModel": "fixed",
  "numberOfSites": 1,
  "prepaymentThresholdTB": 1200.0,
  "prepaymentAmountTB": 1000.0,
  "commitmentPricePerTbPerMonth": 2.5,
  "flexiblePricePerTbPerMonth": 3.5,
  "progressiveSplits": [
    {
      "tb": 5000.0,
      "pricePerTBPerMonth": 3.5
    },
    {
      "tb": 25000.0,
      "pricePerTBPerMonth": 2.625
    },
    {
      "tb": 70000.0,
      "pricePerTBPerMonth": 1.75
    },
    {
      "tb": null,
      "pricePerTBPerMonth": 0.875
    }
  ],
  "introductoryFreeMonths": 3,
  "discountedPriceThresholdTB": 2000.0,
  "discountedPriceFactor": 0.5,
  "serverMonthlyCost": 4500.0,
  "switchMonthlyCost": 500.0,
  "serversPerRack": 6,
  "rackCostPerMonth": 0.0,
  "powerCostPerServerPerMonth": 250.0,
  "peopleManagedServicePerMonth": 395.8333333,
  "connectivityPerMonth": 700.0,
  "otherFixedMonthlyCost": 1000.0,
  "otherVariableMonthlyPerTb": 0.0,
  "minimumServers": 3,
  "rawCapacityPerServerTB": 2880.0,
  "capacityHeadroomFactor": 0.8
}

Curl: Test Report

Post assumptions to the report API and get the canonical monthly attribute model back as JSON.

curl -s https://toc.exaba.com/api/v1/test \
  -H 'content-type: application/json' \
  -d '{
  "scenario": {
    "capacityHeadroomFactor": 0.8,
    "commitmentPricePerTbPerMonth": 2.5,
    "connectivityPerMonth": 700.0,
    "costPerTBPerMonth": 2.0,
    "currency": "USD",
    "discountedPriceFactor": 0.5,
    "discountedPriceThresholdTB": 2000.0,
    "flexiblePricePerTbPerMonth": 3.5,
    "introductoryFreeMonths": 3,
    "minimumServers": 3,
    "monthlyGrowthTB": 80.0,
    "months": 48,
    "numberOfSites": 1,
    "otherFixedMonthlyCost": 1000.0,
    "otherVariableMonthlyPerTb": 0.0,
    "peopleManagedServicePerMonth": 395.8333333,
    "powerCostPerServerPerMonth": 250.0,
    "prepaymentAmountTB": 1000.0,
    "prepaymentThresholdTB": 1200.0,
    "pricingModel": "fixed",
    "progressiveSplits": [
      {
        "pricePerTBPerMonth": 3.5,
        "tb": 5000.0
      },
      {
        "pricePerTBPerMonth": 2.625,
        "tb": 25000.0
      },
      {
        "pricePerTBPerMonth": 1.75,
        "tb": 70000.0
      },
      {
        "pricePerTBPerMonth": 0.875,
        "tb": null
      }
    ],
    "rackCostPerMonth": 0.0,
    "rawCapacityPerServerTB": 2880.0,
    "revenuePerTBPerMonth": 20.0,
    "scenarioName": "Exaba Demo Scenario 1",
    "serverMonthlyCost": 4500.0,
    "serversPerRack": 6,
    "startingTB": 2000.0,
    "switchMonthlyCost": 500.0
  }
}'

Curl: Setup Artifacts

Post the same assumptions to the setup API to generate standalone JavaScript and spreadsheet artifacts on disk.

curl -s https://toc.exaba.com/api/v1/setup \
  -H 'content-type: application/json' \
  -d '{
  "artifacts": {
    "outputDir": "artifacts/root-demo"
  },
  "scenario": {
    "capacityHeadroomFactor": 0.8,
    "commitmentPricePerTbPerMonth": 2.5,
    "connectivityPerMonth": 700.0,
    "costPerTBPerMonth": 2.0,
    "currency": "USD",
    "discountedPriceFactor": 0.5,
    "discountedPriceThresholdTB": 2000.0,
    "flexiblePricePerTbPerMonth": 3.5,
    "introductoryFreeMonths": 3,
    "minimumServers": 3,
    "monthlyGrowthTB": 80.0,
    "months": 48,
    "numberOfSites": 1,
    "otherFixedMonthlyCost": 1000.0,
    "otherVariableMonthlyPerTb": 0.0,
    "peopleManagedServicePerMonth": 395.8333333,
    "powerCostPerServerPerMonth": 250.0,
    "prepaymentAmountTB": 1000.0,
    "prepaymentThresholdTB": 1200.0,
    "pricingModel": "fixed",
    "progressiveSplits": [
      {
        "pricePerTBPerMonth": 3.5,
        "tb": 5000.0
      },
      {
        "pricePerTBPerMonth": 2.625,
        "tb": 25000.0
      },
      {
        "pricePerTBPerMonth": 1.75,
        "tb": 70000.0
      },
      {
        "pricePerTBPerMonth": 0.875,
        "tb": null
      }
    ],
    "rackCostPerMonth": 0.0,
    "rawCapacityPerServerTB": 2880.0,
    "revenuePerTBPerMonth": 20.0,
    "scenarioName": "Exaba Demo Scenario 1",
    "serverMonthlyCost": 4500.0,
    "serversPerRack": 6,
    "startingTB": 2000.0,
    "switchMonthlyCost": 500.0
  }
}'

48-Month Table

The table is empty until you click the render button. If you switch scenarios after the table is already visible, the page automatically re-fetches the selected report and updates the displayed HTML table.

Table not loaded yet.

Framework Graph Demos

Each graph button lazy-loads its chart framework from a CDN, fetches the selected JSON report, and renders one chart per pricing row so you can compare Plotly.js, D3.js, and Chart.js against the same monthly values.

Graphs not loaded yet.

Example HTML Page

This is the standalone HTML pattern for the selected preset: fetch the JavaScript engine, evaluate it, fetch the report, then iterate across months and attributes with getValue(attribute, month).

<!doctype html>
<html lang="en">
  <body>
    <table id="pricing-table"></table>
    <script>
      async function main() {
        const engineSource = await fetch("https://toc.exaba.com/api/v1/library/javascript").then((response) => response.text());
        globalThis.eval(engineSource);

        const payload = await fetch("https://toc.exaba.com/api/v1/demo/report?preset=scenario1").then((response) => response.json());
        const model = ExabaTco.loadSubReport(payload.report);
        const table = document.getElementById("pricing-table");
        const months = model.getMonths();
        const attributes = model.getAttributes();

        const headerRow = document.createElement("tr");
        ["Attribute", "Unit", ...months.map((month) => "Month " + month)].forEach((label) => {
          const cell = document.createElement("th");
          cell.textContent = label;
          headerRow.appendChild(cell);
        });

        const thead = document.createElement("thead");
        thead.appendChild(headerRow);
        table.appendChild(thead);

        const tbody = document.createElement("tbody");
        attributes.forEach((attribute) => {
          const row = document.createElement("tr");
          const labelCell = document.createElement("td");
          labelCell.textContent = attribute.label;
          row.appendChild(labelCell);

          const unitCell = document.createElement("td");
          unitCell.textContent = attribute.unit;
          row.appendChild(unitCell);

          months.forEach((month) => {
            const valueCell = document.createElement("td");
            valueCell.textContent = model.getValue(attribute.key, month);
            row.appendChild(valueCell);
          });

          tbody.appendChild(row);
        });

        table.appendChild(tbody);
      }

      main();
    </script>
  </body>
</html>