# How the Billing and Cost Tracking System Works in Reasonix

> Understand how Reasonix billing and cost tracking works. Learn how it converts token usage to monetary values, aggregates ledger data, and normalizes currencies for clear cost visibility.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: internals
- Published: 2026-08-13

---

**Reasonix calculates session costs by converting provider token usage into monetary values using rate cards, aggregating results in a Ledger, and normalizing currencies for display while preserving immutable billing currencies.**

The **billing and cost tracking system** in Reasonix is built around a core internal package that bridges raw LLM provider usage with user-facing cost visibility. This article explains the complete data flow—from token counting through quote generation to session aggregation—based on the actual source code implementation.

---

## Core Billing Components

Reasonix defines several key types in its internal billing package that work together to track costs accurately:

| Component | Purpose |
|-----------|---------|
| **CostQuote** | Immutable snapshot of cost calculation for a single usage event |
| **Ledger** | Running aggregation of multiple quotes with running totals |
| **RateCard** | Provider-specific pricing (input/output rates per token, currency) |
| **Money** | Currency-aware monetary value with proper rounding |
| **UsageTokens** | Structured token counts (prompt + completion) |
| **QuoteContext** | Display settings and billing mode configuration |

These types appear throughout the codebase in [[`internal/serve/broadcaster.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/serve/broadcaster.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/serve/broadcaster.go), [[`internal/event/costquote_sink.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/event/costquote_sink.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/event/costquote_sink.go), and related files.

---

## Step 1: Recording Provider Usage

Every interaction with an LLM provider generates a `provider.Usage` struct containing token counts. The stats recorder in [[`internal/stats/recorder.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/stats/recorder.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/stats/recorder.go) captures this data and initiates cost calculation:

```go
// internal/stats/recorder.go
func (r *Recorder) recordProviderUsage(
    modelRef string,
    usage *provider.Usage,
    quote *billing.CostQuote,
    usageSource string,
) {
    // Records timestamped usage metrics and associated cost quote
    // for downstream analytics and billing aggregation
}

```

The `usage` parameter contains `PromptTokens` and `CompletionTokens`—the raw inputs for cost calculation.

---

## Step 2: Building a CostQuote with Rate Cards

The `billing.BuildQuote` function transforms token usage into a monetary `CostQuote`. It requires:

- **Usage data** (`billing.UsageTokens`)
- **Rate card** (`billing.RateCard`) from the provider's pricing catalog

Example from test code in [[`internal/eventwire/costquote_compat_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/eventwire/costquote_compat_test.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/eventwire/costquote_compat_test.go):

```go
q := billing.BuildQuote(billing.QuoteInput{
    Usage: billing.UsageTokens{
        PromptTokens:     1_000_000,
        CompletionTokens: 1_000_000,
    },
    Rates: billing.RateCard{
        CacheHit: 0.02,
        Input:    1,
        Output:   2,
        Currency: "CNY",
    },
})

```

Rate cards typically include:

- `Input`: Cost per input token (prompt)
- `Output`: Cost per output token (completion)
- `CacheHit`: Discounted rate for cached context
- `Currency`: Immutable billing currency from provider

---

## Step 3: Ensuring Events Carry Cost Quotes

Before events propagate through the system, [[`internal/event/costquote_sink.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/event/costquote_sink.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/event/costquote_sink.go) ensures every event has a valid `CostQuote` via `EnsureCostQuote`:

```go
// internal/event/costquote_sink.go
func EnsureCostQuote(e Event, ctx *QuoteContext) *billing.CostQuote {
    // Attaches or validates CostQuote on event using context settings
    // Applies display currency normalization if needed
}

```

The `QuoteContext` parameter carries:

- `DisplayCurrency`: User's preferred currency for UI rendering
- `BillingMode`: `PAYG` (pay-as-you-go) or equivalent subscription handling
- `DisplayRequest`: Explicit user request for currency display

---

## Step 4: Aggregating Quotes in the Session Ledger

The broadcaster in [[`internal/serve/broadcaster.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/serve/broadcaster.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/serve/broadcaster.go) maintains a central `Ledger` that accumulates all costs for an active session:

```go
// internal/serve/broadcaster.go
type Broadcaster struct {
    ledger *billing.Ledger
    // ... other fields
}

// Adding a quote to the running total
b.ledger.Add(*e.CostQuote, billing.UsageTokens{
    PromptTokens:     event.Usage.PromptTokens,
    CompletionTokens: event.Usage.CompletionTokens,
})

```

The ledger provides `SessionCostQuote()` which calls `billing.AggregateQuotes` to compute running totals across all events.

---

## Step 5: Currency Handling and Display Normalization

Reasonix strictly separates two currency concepts:

| Concept | Description | Example |
|---------|-------------|---------|
| **Billing Currency** | Immutable currency from provider's list price | `USD`, `CNY` |
| **Display Currency** | User-selected currency for UI rendering | Converted from billing currency |

The `billing.NormalizeCurrency` function standardizes currency codes. Configuration in [[`internal/config/render.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/config/render.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/config/render.go) persists these settings:

```go
// internal/config/render.go
fmt.Fprintf(&b, "[billing]\n")
fmt.Fprintf(&b, "display_currency = %q\n", cfg.DisplayCurrency)
fmt.Fprintf(&b, "billing_currency = %q   # frozen list-price currency\n",

    billing.NormalizeCurrency(providerCurrency))
fmt.Fprintf(&b, "billing_mode = %q\n", cfg.BillingMode)

```

---

## Step 6: Retrieving Balance via Control API

Client applications can query remaining credit through the controller:

```go
// Example client usage against internal/control
balance, err := controller.Balance(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Remaining credit: %s %.2f\n",
    balance.Currency, balance.Amount)

```

This interfaces with the underlying ledger state managed by the broadcaster.

---

## Step 7: Diagnostic Billing Reports

The `reasonix doctor billing` command ([[`internal/doctor/billing.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/doctor/billing.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/doctor/billing.go)) provides operational visibility:

```go
// internal/doctor/billing.go
func CollectBilling() {
    // Gathers pricing data from all configured providers
}

func RenderBillingText() {
    // Human-readable report with normalized currencies
}

```

Key diagnostic functions include:

- `billing.PricingFingerprint`: Identifies provider pricing versions
- `billing.MatchesCatalog`: Validates rate cards against cached pricing data

---

## Complete Usage Example

Here's how components fit together in practice:

```go
package main

import (
    "reasonix/internal/billing"
    "reasonix/internal/provider"
    "reasonix/internal/serve"
)

func trackSessionCost() {
    // Initialize broadcaster with fresh ledger
    broadcaster := serve.NewBroadcaster()
    
    // Simulate provider response
    usage := &provider.Usage{
        PromptTokens:     5000,
        CompletionTokens: 2000,
    }
    
    // Build rate card from provider pricing
    rateCard := billing.RateCard{
        Input:    0.0005,  // $0.50 per 1M tokens
        Output:   0.0015,  // $1.50 per 1M tokens
        Currency: "USD",
    }
    
    // Generate cost quote
    quote := billing.BuildQuote(billing.QuoteInput{
        Usage: billing.UsageTokens{
            PromptTokens:     usage.PromptTokens,
            CompletionTokens: usage.CompletionTokens,
        },
        Rates: rateCard,
    })
    
    // Add to session ledger
    broadcaster.Ledger().Add(quote, billing.UsageTokens{
        PromptTokens:     usage.PromptTokens,
        CompletionTokens: usage.CompletionTokens,
    })
    
    // Retrieve aggregated session cost
    sessionCost := broadcaster.SessionCostQuote()
    println("Session total:", sessionCost.Total().String())
}

```

---

## Summary

Reasonix implements **billing and cost tracking** through a layered architecture:

- **Usage collection** captures raw token counts from providers via the stats recorder
- **Quote generation** converts tokens to monetary values using provider rate cards
- **Event enrichment** ensures every event carries complete cost metadata
- **Ledger aggregation** maintains running session totals with currency precision
- **Display normalization** separates immutable billing currencies from user-facing display
- **Diagnostic tooling** provides operational visibility into pricing configurations

---

## Frequently Asked Questions

### How does Reasonix handle currency conversion for display purposes?

Reasonix stores costs in the provider's **billing currency** (immutable) and applies conversion at display time using `billing.NormalizeCurrency`. The `QuoteContext` tracks the user's `DisplayCurrency` separately from the frozen billing currency, ensuring accurate historical records while allowing flexible UI presentation.

### What billing modes does Reasonix support?

The system supports **PAYG** (pay-as-you-go) as the primary mode, configured via the `[billing]` section in `billing_mode`. The mode affects how quotes are generated and validated but does not change the core token-to-cost calculation logic.

### Where are rate cards sourced from?

Rate cards originate from provider pricing catalogs, validated through `billing.MatchesCatalog` and fingerprinted via `billing.PricingFingerprint`. The doctor billing command ([[`internal/doctor/billing.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/doctor/billing.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/doctor/billing.go)) can refresh and verify these against live provider data.

### Can I query real-time session costs during inference?

Yes. The broadcaster's `SessionCostQuote()` method returns the current aggregated cost from the active ledger. For programmatic access, use the control API's `Balance(ctx)` method as implemented in [[`internal/control/controller.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/controller.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/control/controller.go).