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
import { PricingEngine } from "@zonastery/bursar";
const engine = PricingEngine.fromDict(configDict);
fromDict accepts a canonical config document and returns an engine, or
throws 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.
Calculating cost
const cost = engine.calculate({
operation: "completion",
measures: { input_tokens: 500, output_tokens: 200 },
dimensions: { model: "gpt-4o" },
});
console.log(cost.total.toString());
calculate(metrics, { rateCard }) prices one event. The optional rateCard
key is required when the config contains more than one rate card and the
caller has not otherwise selected one (via getRateCardForPlan).
calculateBatch(metrics, { rateCard }) evaluates an array of UsageMetrics
with the same rate-card selection and returns CostBreakdown[] in the same
order.
getRateCardForPlan(planId) 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.
pricingSchema returns the validated, canonicalized config as a plain object.
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):
import Decimal from "decimal.js";
const engine = PricingEngine.fromDict({
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: {},
});
const cost = engine.calculate({
operation: "completion",
measures: { input_tokens: 2_000_000, output_tokens: 500_000 },
dimensions: { model: "gpt-4o" },
});
// Exact decimals: 2,000,000 × 0.0025/M + 500,000 × 0.0100/M = 0.01
const expected = new Decimal("0.0025")
.times(2)
.plus(new Decimal("0.0100").times("0.5"));
if (!cost.total.equals(expected)) {
throw new Error(`unexpected total: ${cost.total.toString()}`);
}
console.log(cost.total.toString()); // "0.01"
UsageMetrics
| Field | Type | Meaning |
|---|---|---|
operation | string | A key declared in pricing.operations |
measures | Record<string, number | string> | Non-negative billable quantities declared by the operation |
dimensions | Record<string, string | number | boolean> | Typed values used to select the first matching rate rule |
metadata | Record<string, unknown> | 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 operationCredits;
total is the complete quantized result.
| Field | Type |
|---|---|
operationCredits | Decimal |
modelCredits | Decimal |
toolCredits | Decimal |
searchCredits | Decimal |
cacheSavings | Decimal |
fixedCredits | Decimal |
total | Decimal |
breakdown | Record<string, unknown> |
See Pricing for how rate cards, rules, and unmatched actions compose, and Expressions for the supported expression operators and functions.