Skip to main content

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].

reference_id : str | None

reference_type : str | None

total_count : int

type : str

user_id : str