Available Balance Must Exclude Reservations
Available balance must exclude reservations
The balance a user owns and the balance they can spend right now are not always the same number.
Once the system supports reservations, "total balance" stops being the number that should drive gating, UI copy, or concurrency checks. The spendable number is available balance:
available = total - reserved
Sounds obvious. It often is not how products behave.
The rule
If reserved work exists, surface at least these three numbers somewhere in the system:
- total
- reserved
- available
And when the system asks "can this user start another job?", use available, not total.
Anything else teaches the user a lie.
Why this matters
If the UI says "you have 20 credits" while another job has already locked 16 of them, the user does not really have 20 credits. They have 4 credits and a pending promise.
When products hide that distinction, users experience three bad surprises:
- a second job starts and later fails with "insufficient credits"
- a second job is blocked even though the visible balance looked healthy
- support has to explain ledger mechanics the product never bothered to show
That is not a finance problem. It is a product-language problem.
The design consequence
Reservations are not just backend bookkeeping. They are a user-facing state.
That usually means:
- backend eligibility checks use available balance
- UI copy mentions when credits are reserved elsewhere
- transaction history distinguishes holds, spends, and refunds
- monthly-reset logic keeps resettable and non-resettable buckets separate
The last part matters more than it sounds. If top-ups and subscription credits are mixed into one bucket, resets and refunds get weird fast.
Easydeck example
Easydeck now has the right shape:
- subscription credits and top-up credits are separate
- presentation records hold
reservedCredits availableCreditssubtracts other in-flight reservations- the UI can show reserved credits separately from the total
That turns a fuzzy "why can't I generate another deck?" experience into a concrete one: the credits are already spoken for.
Where this generalizes
- cloud quotas
- prepaid API budgets
- gift cards with pending authorizations
- inventory holds in checkout
- booking systems with seats temporarily locked during payment
The principle is always the same: do not present committed capacity as free capacity.