Getting Started
Add usage-based credits to your AI SaaS in minutes — not weeks.
bursar is a drop-in credit calculation engine. Define pricing as math expressions (per-model, per-tool, search/RAG, cache, fixed jobs), connect a database, and start deducting credits. For streaming and agentic workloads, the lease pattern (reserve → settle / release) lets you hold credits during execution and bill the actual cost at the end — with atomic admission control and no double-charges.
Installation
Python:
pip install bursar
# With Supabase store
pip install "bursar[supabase]"
# With PostgreSQL store
pip install "bursar[postgres]"
TypeScript:
npm install @zonastery/bursar
Quick Start — Calculation Only
from bursar import PricingEngine, UsageMetrics
engine = PricingEngine.from_dict({
"version": 1,
"models": {"_default": "input_tokens * 0.001 + output_tokens * 0.003"},
})
result = engine.calculate(
UsageMetrics(model="gpt-4", input_tokens=500, output_tokens=200),
)
print(f"Total credits: {result.total}")
import { PricingEngine } from "@zonastery/bursar";
const engine = PricingEngine.fromDict({
version: 1,
models: { "_default": "input_tokens * (0.001 / 1000) + output_tokens * (0.003 / 1000)" },
});
const cost = engine.calculate({
model: "gpt-4",
inputTokens: 500,
outputTokens: 200,
});
console.log(`Total: ${cost.total}`);
Quick Start — Full Credit Lifecycle
1. Migrate the database
DATABASE_URL="postgresql://user:pass@host:5432/db" bursar migrate
Creates user_credits, credit_transactions, credit_reservations tables (and the pricing, plan, team, cap and analytics objects) — idempotent, safe to run on every deploy. The connection string comes from DATABASE_URL, not the command line.
2. Seed pricing
bursar pricing set - <<'JSON'
{
"version": 1,
"models": {
"gpt-4": "input_tokens * 0.01 + output_tokens * 0.03",
"_default": "input_tokens * 0.001 + output_tokens * 0.003"
}
}
JSON
3. Deduct credits
from bursar import CreditManager, UsageMetrics
from bursar.interface.postgres import PostgresStore
store = PostgresStore("postgresql://user:pass@host:5432/db")
manager = CreditManager(store=store)
manager.load_pricing_from_store()
manager.add_credits("user_abc", 1000)
result = manager.deduct(
user_id="user_abc",
metrics=UsageMetrics(model="gpt-4", input_tokens=500, output_tokens=200),
idempotency_key="chat_session_42",
)
print(f"Deducted {result.amount} credits. Balance: {result.balance_after}")
import { CreditManager, UsageMetrics, HttpxSupabaseStore } from "@zonastery/bursar";
const store = new HttpxSupabaseStore(url, serviceRoleKey);
const manager = new CreditManager(store);
await manager.loadPricingFromStore();
await manager.addCredits("user_abc", 5000);
const result = await manager.deduct(
"user_abc",
{ model: "gpt-4", inputTokens: 500, outputTokens: 200 },
"idempotency-key-123",
);
Language Guides
What's Next?
- Expression Reference — complete syntax and available variables
- Pricing Configuration — structuring your pricing config
- Financial Safety (Leases) — atomic reserve → settle lifecycle, presets, and zero-debt guarantees
- Storage Backends — Supabase, PostgreSQL, or in-memory
- CLI Reference — migration and pricing commands
- Architecture — how bursar works under the hood