Stores
Every Bursar facade is built on a store — the adapter that owns the
database. PostgresStore is the only bundled credit store; PostgresBillingStore
is the bundled billing store; CreditStore is the abstract contract a custom
backend must implement.
PostgresStore
from bursar import PostgresStore
store = PostgresStore(
database_url,
tenant_id=tenant_id,
provider_environment="test",
)
Connects through psycopg2 and runs every mutation as a canonical SQL function
(RPC). Requires the bursar[postgres] extra
(pip install "bursar[postgres]").
| Parameter | Type | Meaning |
|---|---|---|
database_url | str | Postgres connection string (positional) |
tenant_id | str | UUID | Required keyword argument scoping every transaction to one tenant |
provider_environment | "live" | "test" | "sandbox" | Required financial provider namespace |
max_pool_size | int = 20 | Upper bound of the internal ThreadedConnectionPool |
pool | ThreadedConnectionPool | None | Reuse an existing pool instead of creating one |
The store owns its pool: call store.close() to drain it. database_url is
exposed as a read-only property.
PostgresBillingStore
from bursar import PostgresBillingStore
billing_store = PostgresBillingStore(
database_url,
tenant_id=tenant_id,
provider_environment="test",
)
Same shape: database_url (positional), required tenant_id and
provider_environment keywords, and an optional pool (defaults to a fresh
pool, max 10). It wraps all billing
repositories (offer, topup, customer, subscription, event, payment, refund,
invoice, dispute, config) behind one interface. Pass it as billing_store= to
enable billing. Commerce additionally requires commerce_options= with the
provider environment and factories. The store is lazily imported from the top
level and requires the [postgres] extra.
The CreditStore contract
CreditStore is the abstract base class for a custom backend. Implementations
must preserve, for every capability they expose:
- Atomicity — each mutation commits or rolls back as one unit; balances and their ledger rows never diverge.
- Idempotency — a replayed
idempotency_keyreturns the original result instead of applying a second time. - Append-only ledger — history is immutable; corrections are new entries
(
adjustment/refund), never updates. - Credit-lot allocation — credits are consumed lot-by-lot by priority and
expiry (FEFO), with
sweep_expired_creditsexpiring eligible lots. - Stable cursor ordering — every list view orders by
(created_at, entry_id)so cursor pagination never skips or duplicates rows.
Optional capabilities (usage analytics, team management, usage-charge lists,
get_ledger_entry) raise CapabilityNotSupportedError by default on the ABC;
override them if your backend supports them. Billing is a separate hierarchy
(BillingStore/PostgresBillingStore) with its own repositories.
Migrations
The package never applies SQL on construction — neither PostgresStore nor
Bursar runs migrations. Apply the bundled migrations with the bursar
CLI during application setup, before constructing any store:
BURSAR_MIGRATION_DATABASE_URL=postgres://... bursar migrate
The migration command reads BURSAR_MIGRATION_DATABASE_URL. See
CLI for the separate tenant, runtime/config, and local-validation
credentials.
See Storage backends for S3/ClickHouse
adapters and the storage runtime, and custom stores
for a worked example of a custom CreditStore.