bursar.interface.models module
Pydantic schemas for credit store operations.
All store methods accept and return typed Pydantic models rather than raw dicts — validation at the boundary, clarity in the call sites.
Money is represented as decimal.Decimal everywhere (contract §1):
credits are fractional and must never be computed in binary float. Quantization
to 4 dp with ROUND_HALF_UP happens at the money boundary (manager/engine and
on persistence), not inside these models.
class bursar.interface.models.AddCreditsResult(, transaction_id: str, user_id: str, amount: Decimal, new_balance: Decimal, lifetime_purchased: Decimal = Decimal('0'), tier: str = 'default')
Bases: BaseModel
Result of adding credits to a user’s account.
amount : Decimal
lifetime_purchased : Decimal
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
new_balance : Decimal
tier : str
transaction_id : str
user_id : str
class bursar.interface.models.AddTeamMemberResult(, team_id: str = '', user_id: str = '', role: str = 'member')
Bases: BaseModel
Result of adding a team member.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
role : str
team_id : str
user_id : str
class bursar.interface.models.AggregateStatsRow(, total_credits_consumed: Decimal = Decimal('0'), active_users: int = 0, avg_daily_spend: Decimal = Decimal('0'), top_model: str = '', top_user: str = '')
Bases: BaseModel
Aggregate statistics across all users in a time window.
active_users : int
avg_daily_spend : Decimal
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
top_model : str
top_user : str
total_credits_consumed : Decimal
class bursar.interface.models.AllowanceResult(, plan_id: str, allowance_remaining: Decimal, period_start: str, period_end: str)
Bases: BaseModel
Result of checking plan allowance.
allowance_remaining : Decimal
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
period_end : str
period_start : str
plan_id : str
class bursar.interface.models.AvailableResult(, user_id: str, balance: Decimal = Decimal('0'), reserved: Decimal = Decimal('0'), available: Decimal = Decimal('0'))
Bases: BaseModel
Advisory available-balance read: available = balance − reserved (D4/H3).
available is cash-only — it does not include free allowance.
Use can_afford() (which returns CanAffordResult) when you need
the effective spending power including allowance headroom.
available : Decimal
balance : Decimal
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
reserved : Decimal
user_id : str
class bursar.interface.models.BalanceResult(, user_id: str, balance: Decimal = Decimal('0'), lifetime_purchased: Decimal = Decimal('0'))
Bases: BaseModel
Current credit balance for a user.
balance : Decimal
lifetime_purchased : Decimal
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
user_id : str
bursar.interface.models.BillingMode
Billing mode for an operation. strict never lets the balance fall below
the floor at admission (lease worst-case ⇒ zero debt); overdraft permits
the balance to go negative down to a configured floor and always bills the
full actual cost at settle (interface plan §1/D3/D5).
alias of Literal[‘strict’, ‘overdraft’]
class bursar.interface.models.CanAffordResult(, affordable: bool = False, spendable: Decimal = Decimal('0'), worst_case: Decimal = Decimal('0'), reason: str | None = None)
Bases: BaseModel
Advisory affordability check — UI only, non-locking, may be stale (D4/H3).
Never used for admission control; that is exclusively the lease (reserve).
Semantic note (#8): spendable here is the effective spending power:
spendable = balance − active_holds + allowance_remaining
This includes the user’s remaining free allowance so that UI elements (e.g.
a “Send” button) correctly reflect what reserve() will actually admit.
It is therefore different from AvailableResult.available (returned
by get_available()) which is cash-only: balance − active_holds.
affordable : bool
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
reason : str | None
spendable : Decimal
worst_case : Decimal
class bursar.interface.models.CapCheckResult(, capped: bool = False, current_spend: Decimal = Decimal('0'), cap_limit: Decimal = Decimal('0'), action: Literal['deny', 'warn', 'notify'] | None = None, model: str | None = None)
Bases: BaseModel
Result of checking a spend cap.
action is None when no cap applies; consumers default-deny on an
unknown/None action (contract §5, M8).
action : Literal['deny', 'warn', 'notify'] | None
cap_limit : Decimal
capped : bool
current_spend : Decimal
model : str | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
class bursar.interface.models.CheckFeatureResult(, user_id: str, feature: str, value: Any = None, has_feature: bool = False)
Bases: BaseModel
Result of checking a user’s feature entitlement.
feature : str
has_feature : bool
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
user_id : str
value : Any
class bursar.interface.models.CreateTeamResult(, team_id: str = '', name: str = '')
Bases: BaseModel
Result of creating a team.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
name : str
team_id : str
class bursar.interface.models.CreditMetadata(, input_tokens: int | None = None, output_tokens: int | None = None, model: str | None = None, reference_type: str | None = None, reference_id: str | None = None, idempotency_key: str | None = None, fixed_job: str | None = None, **extra_data: Any)
Bases: BaseModel
Flexible metadata attached to credit transactions.
Known fields are typed; arbitrary extras pass through to JSONB.
Merge order (contract §5, M7): the MANAGER merges caller metadata first
and system-seeded fields last, so the system-owned reserved keys
(idempotency_key, model, breakdown_total) always win over
caller-supplied values. This model keeps extra="allow" so callers can
attach arbitrary keys; it does not block that merge order (the manager owns
the merge). Reserved system keys must not be overwritten by caller metadata.
fixed_job : str | None
idempotency_key : str | None
input_tokens : int | None
model : str | None
model_config = {'extra': 'allow'}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
output_tokens : int | None
reference_id : str | None
reference_type : str | None
class bursar.interface.models.DailySpendRow(, date: str = '', total_spend: Decimal = Decimal('0'), transaction_count: int = 0)
Bases: BaseModel
Daily spend aggregation in a time window.
date : str
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
total_spend : Decimal
transaction_count : int
class bursar.interface.models.DeductionResult(, transaction_id: str, user_id: str, amount: Decimal, balance_after: Decimal, allowance_consumed: Decimal = Decimal('0'), idempotent: bool = False, cap_warning: str | None = None, feature_limit_warning: str | None = None, error: str | None = None, tier_breakdown: dict[str, Decimal] | None = None)
Bases: BaseModel
Result of deducting credits after an operation completes.
amount is the net amount charged to the balance (gross cost minus any
free allowance consumed). allowance_consumed is the portion covered by
free allowance, and cap_warning carries a non-blocking warn/notify
spend-cap signal (None when no cap fired). On failure, error carries
a business code (e.g. insufficient_credits, cap_reached) for the
manager to map to a typed exception.
allowance_consumed : Decimal
amount : Decimal
balance_after : Decimal
cap_warning : str | None
error : str | None
feature_limit_warning : str | None
Non-blocking warn/notify signal from a breached FeatureLimit
(parallels cap_warning). None when no feature-limit warning fired.
idempotent : bool
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
tier_breakdown : dict[str, Decimal] | None
transaction_id : str
user_id : str
class bursar.interface.models.FeatureLimit(, max_calls: Annotated[int, Ge(ge=0)], period: Literal['daily', 'weekly', 'monthly', 'yearly'] = 'monthly', action: Literal['deny', 'warn', 'notify'] = 'deny')
Bases: BaseModel
Per-feature invocation-count limit (cadence-based rate limiting).
max_calls bounds how many times a feature may be invoked within one
period window. Windows are calendar-aligned (see
bursar.allowance.resolve_calendar_window()): daily resets at UTC
midnight, weekly on Monday (ISO week), monthly on the 1st,
yearly on Jan 1 — every user resets together, no per-user anchor.
action mirrors SpendCap.action: deny blocks the call (checked
at admission/deduction); warn/notify are non-blocking signals,
checked only on the immediate-charge and settle paths — admission
(reserve/create_lease) only ever enforces deny, exactly like
spend caps (interface plan precedent: deny-only at admission, advisory
elsewhere).
action : Literal['deny', 'warn', 'notify']
max_calls : int
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
period : Literal['daily', 'weekly', 'monthly', 'yearly']
class bursar.interface.models.FeatureLimitResult(, user_id: str, feature: str, limited: bool = False, limit: int = 0, used: int = 0, remaining: int = 0, period_start: str = '', period_end: str = '', action: Literal['deny', 'warn', 'notify'] | None = None)
Bases: BaseModel
Advisory, non-locking read of a per-feature invocation-count limit (UI only).
Mirrors CapCheckResult: limited=False means no FeatureLimit is
configured for this feature on the user’s plan (unlimited) — limit,
used, remaining, and the period bounds are zeroed/empty in that
case, and action is None. Never used for admission control; that is
exclusively the atomic check-and-increment inside deduct/reserve.
action : Literal['deny', 'warn', 'notify'] | None
feature : str
limit : int
limited : bool
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
period_end : str
period_start : str
remaining : int
used : int
user_id : str
class bursar.interface.models.GetUserPlanResult(*, user_id: str, plan_id: str | None = None, plan_name: str | None = None, free_allowance: Decimal = Decimal('0'), features: dict[str, ~typing.Any]=, feature_limits: dict[str, ~bursar.interface.models.FeatureLimit]=, default_billing_mode: Literal['strict', 'overdraft']='strict', per_operation: dict[str, ~bursar.interface.models.OperationPolicy]=, max_concurrent: int | None = None, overdraft_floor: Decimal | None = None, allowance_period: Literal['calendar_month', 'rolling_30d', 'anniversary']='calendar_month', plan_assigned_at: datetime | None = None)
Bases: BaseModel
Result of fetching a user’s current plan.
Carries the plan’s financial-safety policy (default_billing_mode,
per_operation, max_concurrent, overdraft_floor) so the manager
can resolve admission policy without a second round-trip (interface plan §1).
allowance_period and plan_assigned_at (WS9) let the manager resolve
the user’s allowance reset window in one call, without a second round-trip
to the store.
allowance_period : Literal['calendar_month', 'rolling_30d', 'anniversary']
default_billing_mode : BillingMode
feature_limits : dict[str, FeatureLimit]
features : dict[str, Any]
free_allowance : Decimal
max_concurrent : int | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
overdraft_floor : Decimal | None
per_operation : dict[str, OperationPolicy]
plan_assigned_at : datetime | None
plan_id : str | None
plan_name : str | None
user_id : str
class bursar.interface.models.LeaseResult(, lease_id: str, user_id: str, amount: Decimal = Decimal('0'), available: Decimal = Decimal('0'), reserved_total: Decimal = Decimal('0'), billing_mode: Literal['strict', 'overdraft'] = 'strict', expires_at: str = '', error: str | None = None)
Bases: BaseModel
Result of acquiring (or renewing) a lease — the atomic admission hold.
A lease is the only admission control (interface plan §3/D4): it holds
amount against available = balance − Σ(active holds) under one lock so
concurrent operations see each other and max_concurrent is real. On failure
error carries a business code (insufficient_credits, concurrency_limit,
cap_reached, feature_not_entitled, feature_limit_reached,
invalid_amount, lease_not_found, lease_expired, lease_released)
for the manager to map to a typed exception.
amount : Decimal
available : Decimal
billing_mode : BillingMode
error : str | None
expires_at : str
lease_id : str
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
reserved_total : Decimal
user_id : str
class bursar.interface.models.OperationPolicy(, billing_mode: Literal['strict', 'overdraft'] = 'strict', max_concurrent: int | None = None, overdraft_floor: Decimal | None = None)
Bases: BaseModel
Per-operation financial-safety policy (interface plan §1).
Resolved per call as: explicit arg → PlanDefinition.per_operation[type] →
plan default → the manager’s constructor preset. max_concurrent bounds the
number of simultaneously-active leases for an operation type; overdraft_floor
(only meaningful when billing_mode == "overdraft") is the negative balance
floor admission is allowed down to.
billing_mode : BillingMode
max_concurrent : int | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
overdraft_floor : Decimal | None
class bursar.interface.models.PlanDefinition(, id: str, name: str, free_allowance: Annotated[Decimal, Ge(ge=0)] = Decimal('0'), rate_overrides: dict[str, str] | None = None, features: dict[str, Any] | None = None, feature_limits: dict[str, FeatureLimit] | None = None, default_billing_mode: Literal['strict', 'overdraft'] = 'strict', per_operation: dict[str, OperationPolicy] | None = None, max_concurrent: int | None = None, overdraft_floor: Decimal | None = None, allowance_period: Literal['calendar_month', 'rolling_30d', 'anniversary'] = 'calendar_month')
Bases: BaseModel
Definition of a subscription plan with free allowance and rate overrides.
Beyond allowance/rates/features, a plan carries the financial-safety policy
(interface plan §1): a default_billing_mode for the whole plan, optional
per_operation overrides keyed by operation type, and plan-wide
max_concurrent / overdraft_floor defaults.
Accepts billing_mode as a short-form alias for default_billing_mode
so configs written with the shorter key work without changes.
allowance_period : Literal['calendar_month', 'rolling_30d', 'anniversary']
Free-allowance reset window (WS9). calendar_month (default) resets on
the 1st of each UTC month; rolling_30d/anniversary anchor to when
the user was assigned the plan (GetUserPlanResult.plan_assigned_at).
default_billing_mode : BillingMode
feature_limits : dict[str, FeatureLimit] | None
Per-feature invocation-count limits, keyed by feature name. Independent of
features (boolean/value entitlement) — a feature can be entitled and
rate-limited at the same time.
features : dict[str, Any] | None
free_allowance : Decimal
id : str
max_concurrent : int | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
name : str
overdraft_floor : Decimal | None
per_operation : dict[str, OperationPolicy] | None
rate_overrides : dict[str, str] | None
class bursar.interface.models.PricingConfigData(*, version: ~typing.Literal[1] = 1, models: dict[str, str], tools: dict[str, str] = , search: str | None = None, cache: str | None = None, fixed: dict[str, ~decimal.Decimal] = , min_balance: ~typing.Annotated[~decimal.Decimal, ~annotated_types.Ge(ge=0)] = Decimal('0'), signup_bonus: int = 50, plans: dict[str, ~bursar.interface.models.PlanDefinition] | None = None, tiers: dict[str, ~bursar.interface.models.TierDefinition] | None = None)
Bases: BaseModel
Pricing configuration schema.
Mirrors the YAML config structure used by PricingEngine.
Unified format with optional plan definitions.
cache : str | None
fixed : dict[str, Decimal]
min_balance : Decimal
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
models : dict[str, str]
plans : dict[str, PlanDefinition] | None
search : str | None
signup_bonus : int
tiers : dict[str, TierDefinition] | None
tools : dict[str, str]
version : Literal[1]
class bursar.interface.models.PricingConfigHistoryItem(, id: str, version: int, label: str | None = None, active: bool = False, created_at: str = '')
Bases: BaseModel
Lightweight summary for pricing version listing.
active : bool
created_at : str
id : str
label : str | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
version : int
class bursar.interface.models.PricingConfigResult(, id: str, config: PricingConfigData, version: int = 1, label: str | None = None)
Bases: BaseModel
Versioned pricing configuration fetched from the store.
config : PricingConfigData
id : str
label : str | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
version : int
class bursar.interface.models.RefundResult(, refund_transaction_id: str, original_transaction_id: str, user_id: str, amount: Decimal = Decimal('0'), new_balance: Decimal = Decimal('0'), error: str | None = None, tier_breakdown: dict[str, Decimal] | None = None)
Bases: BaseModel
Result of refunding a credit deduction.
On failure, error carries a business code (e.g. already_refunded,
over_refund, not_found) so the manager can reject over-refunds and
duplicates before emitting a success event (contract §4).
amount : Decimal
error : str | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
new_balance : Decimal
original_transaction_id : str
refund_transaction_id : str
tier_breakdown : dict[str, Decimal] | None
user_id : str
class bursar.interface.models.ReleaseResult(, lease_id: str, user_id: str, released: bool = False, reason: str | None = None)
Bases: BaseModel
Result of releasing a lease without charging (interface plan §3).
Idempotent and safe on missing/already-finalized leases: released is
True only when this call transitioned an active/expired lease to released.
reason is one of released, already_released, already_settled,
not_found — never a bare void (resolves H1).
lease_id : str
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
reason : str | None
released : bool
user_id : str
class bursar.interface.models.SetUserPlanResult(, user_id: str, plan_id: str)
Bases: BaseModel
Result of assigning a plan to a user.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
plan_id : str
user_id : str
class bursar.interface.models.SetupResult(*, tables_created: list[str] = , rpcs_created: list[str] = , errors: list[str] = )
Bases: BaseModel
Report of what the setup step created or updated.
errors : list[str]
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
rpcs_created : list[str]
property success : bool
tables_created : list[str]
class bursar.interface.models.SpendByModelRow(, model: str = '', total_spend: Decimal = Decimal('0'), transaction_count: int = 0)
Bases: BaseModel
Aggregated spend for a single model in a time window.
model : str
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
total_spend : Decimal
transaction_count : int
class bursar.interface.models.SpendByUserRow(, user_id: str = '', total_spend: Decimal = Decimal('0'), transaction_count: int = 0)
Bases: BaseModel
Aggregated spend for a single user in a time window.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
total_spend : Decimal
transaction_count : int
user_id : str
class bursar.interface.models.SpendCap(, user_id: str = '', type: Literal['daily', 'monthly'] = 'daily', model: str | None = None, limit: Annotated[Decimal, Ge(ge=0)] = Decimal('0'), action: Literal['deny', 'warn', 'notify'] = 'deny')
Bases: BaseModel
Configuration for a per-user spend cap.
populate_by_name=True so the field accepts both its name (cap_type)
and its alias (type) on input, standardizing (de)serialization across
the camelCase/snake_case boundary (contract §5, M14-models).
action : Literal['deny', 'warn', 'notify']
cap_type : Literal['daily', 'monthly']
limit : Decimal
model : str | None
model_config = {'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
user_id : str
class bursar.interface.models.SweepResult(, expired_count: int = 0, expired_amount: Decimal = Decimal('0'), dry_run: bool = False, expired_by_tier: dict[str, Decimal] | None = None)
Bases: BaseModel
Result of sweeping expired credits.
dry_run : bool
expired_amount : Decimal
expired_by_tier : dict[str, Decimal] | None
expired_count : int
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
class bursar.interface.models.Team(, team_id: str = '', name: str = '', balance: Decimal = Decimal('0'), member_count: int = 0, created_at: str = '')
Bases: BaseModel
A team with a shared credit balance pool.
balance : Decimal
created_at : str
member_count : int
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
name : str
team_id : str
class bursar.interface.models.TeamBalanceResult(, team_id: str = '', name: str = '', balance: Decimal = Decimal('0'), member_count: int = 0)
Bases: BaseModel
Result of fetching team balance.
balance : Decimal
member_count : int
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
name : str
team_id : str
class bursar.interface.models.TeamDeductionResult(, transaction_id: str = '', team_id: str = '', user_id: str = '', amount: Decimal = Decimal('0'), team_balance_after: Decimal = Decimal('0'), error: str | None = None)
Bases: BaseModel
Result of deducting credits from a team pool.
amount : Decimal
error : str | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
team_balance_after : Decimal
team_id : str
transaction_id : str
user_id : str
class bursar.interface.models.TeamMember(, user_id: str = '', role: str = '', spend_cap: Decimal | None = None, total_spent: Decimal = Decimal('0'))
Bases: BaseModel
A member of a team with optional spend cap.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
role : str
spend_cap : Decimal | None
total_spent : Decimal
user_id : str
class bursar.interface.models.TierBalance(, tier_key: str, name: str = '', priority: int = 0, expires: bool = False, balance: Decimal = Decimal('0'))
Bases: BaseModel
Balance for a single credit tier.
balance : Decimal
expires : bool
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
name : str
priority : int
tier_key : str
class bursar.interface.models.TierBalancesResult(, user_id: str, tiers: list[TierBalance], total_balance: Decimal)
Bases: BaseModel
Per-tier balance breakdown for a user, ordered by priority ascending.
total_balance mirrors BalanceResult.balance — the maintained
aggregate cache, kept equal to the sum of tier balances.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
tiers : list[TierBalance]
total_balance : Decimal
user_id : str
class bursar.interface.models.TierDefinition(, name: str, priority: int, expires: bool = False, default_ttl_days: int | None = None, allow_overdraft: bool = False, is_default: bool = False)
Bases: BaseModel
Definition of a credit tier controlling deduction priority and expiry.
priority controls deduction order (lower drains first; ties broken by
key ascending, not an error). expires marks whether credits granted
into this tier are subject to expiry; when True, default_ttl_days
(if set) fixes the default expiry window used by add_credits calls
that omit an explicit expires_at. At most one tier may set
allow_overdraft=True (the sole tier permitted to absorb overdraft
debt) and at most one may set is_default=True (untagged
add_credits() calls land here) — enforced by config validation.
allow_overdraft : bool
default_ttl_days : int | None
expires : bool
is_default : bool
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
name : str
priority : int
class bursar.interface.models.TopUserRow(, user_id: str = '', total_spend: Decimal = Decimal('0'))
Bases: BaseModel
Top-spending user in a time window.
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
total_spend : Decimal
user_id : str
class bursar.interface.models.TransactionRow(, id: str = '', user_id: str = '', amount: Decimal = Decimal('0'), type: str = '', reference_type: str | None = None, reference_id: str | None = None, metadata: dict[str, Any] | None = None, created_at: str = '', total_count: int = 0)
Bases: BaseModel
A single credit transaction row.
amount : Decimal
created_at : str
id : str
metadata : dict[str, Any] | None
model_config = {}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].