One of the biggest problems with AI products: nobody knows how much they’ve used and how much they have left. A user sees “12,450 credits” and has no idea if that means an hour or a month. Internal numbers like credits, tokens, and context windows are meaningless to most people.
A few days ago I redesigned the billing/limits page in CoreSynth — specifically for Alex. The goal was simple: stop showing raw numbers and start showing what users actually need to know.
What changed
Progress bars instead of numbers
Before, the page showed 12,450 / 50,000 credits. Now it shows 74% and a progress bar that changes green → orange → red as you approach the limit. Users can tell at a glance whether they’re fine or should slow down.
BEFORE: 12,450 / 50,000 credits
AFTER: [████████░░] 74% · 26% remaining
The color updates dynamically:
- Green — under 70%, all good
- Orange — 70–90%, heads up
- Red — over 90%, approaching the ceiling
Tokens instead of credits
Before, there were “credits” and “tokens” columns side by side — double confusion. Now there are just tokens, split into three clear categories:
BEFORE: Input | Output | Cache | Credits
AFTER: Context | Cache | Total
“Credits” disappeared from the customer view entirely. They’re an internal unit that means nothing to anyone outside. Instead, users see:
- Context — tokens spent on input and output (the AI’s actual work)
- Cache — tokens saved through caching (bonus)
- Total — the sum
User-cost modal
A new modal that shows users a worst-case cost projection. Instead of saying “you have 50,000 credits,” I say “in the worst case this will cost you this much — but thanks to caching, it’ll likely be less.”
MAX (ceiling) Week / Month
Cache hit: ~40% your real cost will be lower
Users know what they’re getting into upfront. No surprise on the invoice.
One page for everything
Before, limits were scattered across multiple routes — each service had its own. Now there’s one canonical page /account/alex/limits that shows everything in one place. If a user has multiple orders, they can switch between them via the ?order= parameter.
The technical side
A few things needed to happen behind the scenes:
- Single source of truth for limits — all limits (chat and proxy API) now pull from one database table. Before they were scattered across configs, hardcoded fallbacks, and spreadsheets.
- Unified baseline model — one configuration point for the base model, instead of hardcoded values in two different environments.
- Pooled billing — the page handles the case where one user pays for AI but multiple people use it. It shows a per-user breakdown.
- Progress bar helper —
_usedPercentcalculates the percentage, the frontend just renders the color and width.
BEFORE AFTER
───────────────────────────── ─────────────────────────────
50 route paths 1 canonical page
Hardcoded limits in 3 places DB table (single source)
Raw credit counts Percentage progress bars
4 token columns 3 (Context|Cache|Total)
No cost projection User-cost modal (worst-case)
Why this matters
Billing in AI products is still in its infancy. Most SaaS tools just show a number and call it a day. But with AI it’s more complex — usage depends on the model, context window, caching, and how much the AI decides to elaborate. Showing raw numbers without context is like telling someone “you used 12,450 electricity” without a unit.
The goal was: users must know where they stand at first glance, and see details when they need them. No surprises, no “what’s a credit?”, no jumping between three pages.
The best billing is one users don’t have to think about — while everything still makes sense.
Why I’m writing about this
Because this is a typical case where 80% of the work is decision-making and 20% is implementation. Thinking of “progress bar instead of numbers” takes a minute. Making it work with pooled billing, caching, multiple models, and language variants — that takes an afternoon.
It’s also an example of how a small UX decision can have a big impact on how users perceive the entire product. Transparent billing = trust in the product.