> ## Documentation Index
> Fetch the complete documentation index at: https://tanso.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Credit forecasts

> Embeddable, provider-neutral credit and usage burndown forecasting for your dashboard

[`credit-estimator`](https://github.com/tansohq/credit-estimator) is a
separate open-source project, published to npm under the `@tansohq` scope.
It forecasts credit or usage runway from observed history and explicit
low/base/high burn assumptions, and renders the result as an accessible React
widget.

It is **provider-neutral**: the deterministic core and React UI have no
Tanso dependency and work the same way for any host. An optional adapter maps
a Tanso snapshot into the same neutral input any other host would supply.

<Note>
  This is a read-only forecasting tool. It does not own wallets, ledgers,
  usage events, entitlements, subscriptions, or payments — it projects a
  balance from data you supply. It never writes back to Tanso.
</Note>

## Packages

| Package                           | Purpose                                                            |
| --------------------------------- | ------------------------------------------------------------------ |
| `@tansohq/credit-forecast-schema` | Provider-neutral Zod schemas and TypeScript contracts              |
| `@tansohq/credit-forecast-core`   | Deterministic burndown calculation, browser and Node.js compatible |
| `@tansohq/credit-burndown-react`  | Controlled, accessible React components                            |
| `@tansohq/credit-forecast-json`   | Deterministic JSON import and export                               |
| `@tansohq/credit-forecast-csv`    | Portable multi-file CSV import and export                          |
| `@tansohq/credit-forecast-tanso`  | Optional Tanso snapshot-to-neutral mapping                         |

All are ESM-only; CommonJS hosts need dynamic `import()`. React peers are
`^18.2 || ^19`.

## Calculate a forecast

```bash theme={null}
npm install @tansohq/credit-forecast-core
```

```typescript theme={null}
import { forecastCreditUsage } from "@tansohq/credit-forecast-core";

const result = forecastCreditUsage({
  schemaVersion: "1.0",
  methodologyVersion: "1.0",
  asOf: "2026-01-03",
  period: {
    startDate: "2026-01-01",
    endDate: "2026-01-06",
    allocation: "500",
    lowBalanceThreshold: "50",
  },
  lookbackDays: 2,
  dailyUsage: [
    { date: "2026-01-01", creditsUsed: "40" },
    { date: "2026-01-02", creditsUsed: "60" },
  ],
  balance: { current: "400", schedule: [] },
  scenarios: [
    { key: "low", burnMultiplier: "0.75" },
    { key: "base", burnMultiplier: "1" },
    { key: "high", burnMultiplier: "1.5" },
  ],
});
```

All credit values are canonical decimal strings, not floats. The core reads
no clock, filesystem, network, or credentials — `asOf` is explicit, and
invalid input throws a structured `ForecastValidationError`.

## Plan credits before committing

The same core package answers the buyer-side question — "how many credits
does this period need?" — with no usage history:

```typescript theme={null}
import { planCreditUsage } from "@tansohq/credit-forecast-core";

const plan = planCreditUsage({
  schemaVersion: "1.0",
  methodologyVersion: "1.0",
  period: { startDate: "2026-02-01", endDate: "2026-03-01" },
  metricEstimates: [
    { key: "api-calls", label: "API calls", estimatedUnits: "1000", creditsPerUnit: "0.5" },
    { key: "reports", label: "Generated reports", estimatedUnits: "20", creditsPerUnit: "5" },
  ],
  allocation: "700",
  scenarios: [
    { key: "low", burnMultiplier: "0.8" },
    { key: "base", burnMultiplier: "1" },
    { key: "high", burnMultiplier: "1.25" },
  ],
});
```

Each metric's planned credits is `estimatedUnits × creditsPerUnit`, scenarios
scale that by their multipliers, and the optional `allocation` yields
utilization, surplus or shortfall, and a
`WITHIN_ALLOCATION` / `OVER_ALLOCATION` status per scenario. Everything is an
explicit input — the calculator never recommends weights or allocations,
never produces money amounts, and never predicts usage from history. Invalid
input throws a structured `PlanValidationError`.

For a Tanso host, no adapter is needed: `creditsPerUnit` is the resolved
weight your [tariff](/credit-weights) returns as `creditQuote.weight`, and
`allocation` is the candidate credit grant.

The React package renders it with buyer-facing defaults (Conservative /
Expected / Aggressive scenario labels, an allocation meter, a per-metric
breakdown, and the calculation trace):

```tsx theme={null}
import { planCreditUsage } from "@tansohq/credit-forecast-core";
import { CreditPlan } from "@tansohq/credit-burndown-react";
import "@tansohq/credit-burndown-react/styles.css";

const result = planCreditUsage(input);

<CreditPlan.Root input={input} result={result}>
  <CreditPlan.Summary />
  <CreditPlan.Scenarios />
  <CreditPlan.Breakdown />
  <CreditPlan.Warnings />
  <CreditPlan.Trace />
</CreditPlan.Root>;
```

## Embed the widget

```bash theme={null}
npm install @tansohq/credit-burndown-react
```

```tsx theme={null}
import { forecastCreditUsage } from "@tansohq/credit-forecast-core";
import { CreditBurndown } from "@tansohq/credit-burndown-react";
import "@tansohq/credit-burndown-react/styles.css";

const result = forecastCreditUsage(input);

<CreditBurndown.Root input={input} result={result}>
  <CreditBurndown.Summary />
  <CreditBurndown.Chart />
  <CreditBurndown.Scenarios />
  <CreditBurndown.Warnings />
  <CreditBurndown.Breakdown />
</CreditBurndown.Root>;
```

The component is result-controlled: you calculate (in your browser or your
backend) and pass both `input` and `result` in as props. It has no fetch,
authentication, persistence, or billing dependency, so it never resolves a
stale forecast on its own. Theme it with the `--credit-burndown-*` CSS
variables, override any message string, inject your own action slot, and
control the selected scenario from outside.

## Feeding it from Tanso

`@tansohq/credit-forecast-tanso` maps a Tanso snapshot plus explicit
assumptions into the same `ForecastInput` any other host would build by hand:

```typescript theme={null}
import { forecastCreditUsage } from "@tansohq/credit-forecast-core";
import {
  mapTansoSnapshotToForecastInput,
  type TansoForecastAssumptions,
  type TansoForecastSnapshot,
} from "@tansohq/credit-forecast-tanso";

const snapshot: TansoForecastSnapshot = {
  sourceSchemaVersion: "1.0",
  asOf: "2026-01-03",
  currentBalance: "400",
  dailyUsage: [
    { date: "2026-01-01", creditsUsed: "40" },
    { date: "2026-01-02", creditsUsed: "60" },
  ],
};

const assumptions: TansoForecastAssumptions = {
  schemaVersion: "1.0",
  methodologyVersion: "1.0",
  period: {
    startDate: "2026-01-01",
    endDate: "2026-01-06",
    allocation: "500",
    lowBalanceThreshold: "50",
  },
  lookbackDays: 2,
  scheduledBalanceDeltas: [],
  scenarioMultipliers: { low: "0.75", base: "1", high: "1.5" },
};

const input = mapTansoSnapshotToForecastInput(snapshot, assumptions);
const result = forecastCreditUsage(input);
```

<Warning>
  The adapter does not fetch data, call a Tanso API, or reconstruct a
  balance — you assemble `snapshot` from your own authenticated call to the
  [credits Client API](/credits), such as a pool's
  `/pools/{poolId}/transactions` history. There is no automatic Tanso source
  connector. Mapping failures throw `TansoMappingError`, whose `toJSON()`
  returns `{ code: "TANSO_MAPPING_FAILED", issues }`.
</Warning>

Tanso remains authoritative for actual balances, grants, deductions, and
billing state. The forecast is a projection from the snapshot you supplied at
call time — if it and Tanso's current state have since diverged, refetch the
snapshot and recalculate. Nothing in this package reserves credits, alters an
entitlement decision, or writes back to the ledger.

See the
[optional Tanso adapter boundary](https://github.com/tansohq/credit-estimator/blob/main/docs/tanso-integration.md)
for the full contract, including what the adapter is forbidden from doing.
