PricingEngine
PricingEngine is Bursar's database-free operation-pricing core. It validates
the same canonical configuration as the rest of the SDK and prices
UsageMetrics events without any store, connection, or facade.
Creating an engine
from bursar import PricingEngine
engine = PricingEngine.from_dict(config_dict)
from_dict accepts a canonical config document and returns an engine, or
raises ConfigError. Unknown fields, undeclared measures or dimensions,
invalid matcher types, and unsafe cross-references are rejected at
construction. Credit accounting is a fixed Bursar convention rather than a
configuration field; plan rank has an authoring default.
The engine is safe to construct from a config you already validated with
load_config_from_dict.
Calculating cost
from bursar import UsageMetrics
cost = engine.calculate(
UsageMetrics(
operation="completion",
measures={"input_tokens": 500, "output_tokens": 200},
dimensions={"model": "gpt-4o"},
)
)
print(cost.total)
calculate(metrics, *, rate_card=None) prices one event. The optional
rate_card key is required when the config contains more than one rate card
and the caller has not otherwise selected one (via
get_rate_card_for_plan).
calculate_batch(metrics, *, rate_card=None) evaluates a list of
UsageMetrics with the same rate-card selection and returns a
list[CostBreakdown] in the same order.
get_rate_card_for_plan(plan_id) returns the rate-card key referenced by a
configured plan — the canonical way to resolve the rate card for a user whose
plan is known.
pricing_schema returns the validated, canonicalized config as a dict.
Example
Using the canonical demo configuration (pricing.operations.completion,
rate card standard, per-million-token rates for gpt-4o/gpt-4o-mini, and
an expression-based fallback for unmatched models):
from decimal import Decimal
config = {
"version": 1,
"pricing": {
"operations": {
"completion": {
"measures": {
"input_tokens": {"unit": "token"},
"output_tokens": {"unit": "token"},
"cache_read_tokens": {"unit": "token"},
},
"dimensions": {"model": {"type": "string"}},
}
},
"rate_cards": {
"standard": {
"operations": {
"completion": {
"rules": [
{
"when": {"model": {"op": "in", "values": ["gpt-4o", "gpt-4o-mini"]}},
"charge": {
"type": "sum",
"components": [
{"type": "per_unit", "measure": "input_tokens", "rate": "0.0025", "unit_size": "1000000"},
{"type": "per_unit", "measure": "output_tokens", "rate": "0.0100", "unit_size": "1000000"},
{"type": "per_unit", "measure": "cache_read_tokens", "rate": "0.00125", "unit_size": "1000000"},
],
},
}
],
"unmatched": {
"action": "charge",
"charge": {
"type": "expression",
"formula": "input_tokens * 0.005 + output_tokens * 0.015",
},
},
}
}
}
},
},
"credits": {},
}
engine = PricingEngine.from_dict(config)
cost = engine.calculate(
UsageMetrics(
operation="completion",
measures={"input_tokens": 2_000_000, "output_tokens": 500_000},
dimensions={"model": "gpt-4o"},
)
)
assert cost.total == Decimal("0.01") # 2,000,000 × 0.0025/M + 500,000 × 0.0100/M
UsageMetrics
| Field | Type | Meaning |
|---|---|---|
operation | str | A key declared in pricing.operations |
measures | dict[str, Decimal] | Non-negative billable quantities declared by the operation |
dimensions | dict[str, str | Decimal | bool] | Typed values used to select the first matching rate rule |
metadata | dict[str, Any] | Caller metadata; it does not participate in pricing |
Declared measures omitted by the caller are treated as zero. Required dimensions must be present. Undeclared measures or dimensions are rejected.
CostBreakdown
All monetary fields are Decimal values quantized to six decimal places with
half-up rounding. Operation pricing is reported in operation_credits;
total is the complete quantized result.
| Field | Type |
|---|---|
operation_credits | Decimal |
model_credits | Decimal |
tool_credits | Decimal |
search_credits | Decimal |
cache_savings | Decimal |
fixed_credits | Decimal |
total | Decimal |
breakdown | dict[str, Any] |
See Pricing for how rate cards, rules, and unmatched actions compose, and Expressions for the supported expression operators and functions.