Billing looks simple at the start. One product. One plan. A handful of customers. You wire up Stripe, push some configs, and move on. It works, until it doesn’t.
As your product evolves, so does your pricing. You experiment with usage tiers, roll out regional pricing, introduce AI-related credits, or move to prepaid wallets.
The marketing and product teams treat pricing as a growth lever which it is, but behind every pricing change is a billing implication that someone on the engineering team has to handle.
What starts as a clean setup becomes a patchwork of overrides, edge case conditionals, and spreadsheet-based fixes.
Billing logic doesn’t break all at once, it accumulates debt slowly, until a single customer complaint forces you to trace logic across Stripe configs, backend services, and support notes.
And suddenly, you’re debugging a “routine invoice issue” at 2 a.m. because someone on Slack said the numbers look off.
That’s the trap. You think billing is solved when the invoice goes out.
But real billing logic touches every critical system revenue, product behavior, finance workflows, and customer trust. And no one team fully owns it.
That’s what makes billing an engineering problem.
The Illusion of Simplicity
At a glance, billing feels like a solved problem.
You multiply usage by price. You send an invoice. Done.
Except, real-world billing logic is anything but simple. It doesn’t live in one place. It doesn’t follow one model. And it certainly doesn’t stay stable.
The moment your pricing strategy evolves, your systems need to know:
- What qualifies as billable usage?
- Do credits apply before or after usage thresholds?
- Is this customer on an old grandfathered plan or the new rollout?
- Do we bill on calendar cycles or based on subscription start dates?
These aren’t questions you answer once. You revisit them every time product launches a new feature, or sales experiments with a new deal structure.
And yet, billing logic, arguably the most sensitive module in your system is split across:
- Stripe configs that abstract complexity behind dropdowns
- Backend services with hardcoded overrides
- Airtable sheets tracking credits
- Notion pages for the support team
- And Slack threads where bugs go to hide
By the time something breaks, it’s no longer about “who wrote this logic.” It’s “where is this logic even defined?”
Why Engineers Always End Up Owning Billing
No one sets out to make billing an engineering problem. But they inevitably do.
Here’s the reality most teams live through:
- Pricing changes come more often
- Overrides start as exceptions but become business-as-usual.
- Each team “solves” their part in isolation, and the glue lives in engineering.
So even though the ownership is distributed, the blast radius isn’t.
When finance can’t explain a refund, product can’t version a plan, or customer support gets asked why two users were billed differently, engineering gets pulled in.
Every billing sprint feels like a root-cause investigation of something you never intended to build in the first place.
Basic Billing Tools Don’t Help
Most basic SaaS billing platforms come with a fatal assumption: You’ll mold your pricing to fit their UI.
But real pricing doesn’t look like dropdowns and toggles.
It looks like:
- Hybrid models mixing usage-based and seat-based billing
- Limited-time grants with conditional expiry rules
- Custom invoice logic for specific enterprise deals
- Multiple billing cycles coexisting in the same account
To get that working in most systems, you end up doing one of two things:
- Exporting data, transforming it in code, and uploading results manually
- Writing glue code that sits between your billing provider and the rest of your stack
- Neither scales. Both increase fragility. And neither gives you answers when things go wrong.
Worse, there’s no way to test invoice outputs before sending them.
You’re just trusting that your conditionals and Stripe configs align perfectly.
What Infra-Grade Billing Should Look Like
If billing affects revenue, customer experience, and finance workflows, it needs to be treated like infrastructure.
That means:
- Every credit rule and aggregation logic is source-controlled
- You can simulate invoice outputs before pushing to production
- Your business rules live in one system, not scattered across four
- You have visibility into “why” an invoice was calculated the way it was
This isn’t about building your own Stripe. It’s about building the thing around Stripe that every engineering team duct tapes eventually.
How We Built Flexprice
Flexprice is our take on what a real billing engine should look like when treated as infrastructure, not as an afterthought.
It gives you:
- Composable logic blocks for usage, credits, wallets, and plans
- Custom aggregation strategies like count unique, latest, sum, or plug in your own
- Wallet-based accounting to track balance changes in real time
- Grant systems to attach credits to plans or offer one-time incentives
- Invoice generation for both calendar-aligned and rolling subscriptions
- Offline payment support with full balance reconciliation
And everything is:
- Inspectable
- Testable
- Source-controlled
You get the flexibility to model your own logic, not just configure someone else’s abstraction. Because pricing will change.
And your engineering team shouldn’t have to debug broken invoices at 2:00 AM every time it does.
⭐ Star us on GitHub to follow our progress
🤝 Join our community to share feedback and collaborate.
Top comments (1)
Was dealing with something similar recently. Started simple, but over time the billing logic became messy and hard to track.
Flexprice looks promising. Starred the repo curious to see how it evolves.