In August 2026, while calculating an upgrade for one customer, my AI assistant found a database column it had assumed was empty. It held the price each customer had actually agreed to pay. Almost every price had been negotiated one by one, and they varied a great deal from customer to customer.
Until that day, every estimate the assistant made had multiplied the number of customers by the price printed on our website. Every one of those estimates was wrong, because almost nobody paid exactly that price.
The price on your website is the start of a conversation. The price stored in your database is what pays your bills. Good pricing design keeps the two connected.
The short answer
Price a SaaS in six parts: plans, limits, add-ons, a trial, an optional free plan and a currency. Charge for what grows with your customer, such as users and branches. Keep prices in the database, calculate totals instead of typing them, and lock every paid module on every door so it stays closed when the system is unsure.
The six parts of SaaS pricing
- Plans: the packages a customer chooses between.
- Limits: what each plan allows, such as users or branches.
- Add-ons: extra modules sold separately.
- The trial: how long new customers try everything before paying.
- A free plan (optional): a permanent free tier, funded by ads or used as a path to paid plans.
- Currency: what local customers see and what foreign visitors see.
It resembles a phone contract: a few plans with limits, extras at extra cost, sometimes a free first month. Customers already understand this shape.
Five principles matter more than any number. Charge for what grows with your customer's success, because the day a company hires another employee or opens a second branch is the day it can afford more. Keep prices in the database, not in the app's code. Calculate totals, never type them. Make sure the plan page matches what the system really locks. And make paid modules fail closed.
How we did it in KashBoss
Design the data for negotiation
In business-to-business markets, prices get negotiated. Pretending otherwise pushes the negotiation into places your system cannot see.
For each customer we stored one number, a hand-typed "next renewal amount" that mixed the plan, any extra users or branches and any agreed discount. The only screen with that field was the "renew and record a payment" screen, and it refused to save unless the amount paid was above zero. So when one customer's agreed renewal price was entered, the system saved it as a cash payment that never happened. Revenue and cash balance rose by money we never received, and with everything squeezed into one number we could not see who still owed us.
We rebuilt subscriptions as lines, like an invoice: the plan, each add-on with its quantity and an agreed discount if any. Each item has a default price in a catalog, a customer line can carry its own agreed price, and the total is calculated from the lines. "Due" and "received" are stored separately, and a wrong receipt is reversed with a correction note instead of being deleted.
Sell big modules as add-ons, and describe them exactly
Some modules are too valuable, or too costly for us to run, to put inside every plan. Our field sales tracking taught us to describe precisely what is paid for. A sales rep can sell, collect cash and print invoices on any normal plan, as one of its users. What costs extra is following the rep: visits recorded with location, planned routes, a daily report and live map tracking. It was also our first item with a different billing cycle, so one subscription can now hold a yearly plan and monthly add-ons together.
Keep prices in the database
At first a price was typed straight into our landing page code, and some marketing text promised "no fee for extra users" while the real price said otherwise. Nobody lied on purpose. The text was written once and never connected to the real number. Now one database function returns every add-on's name, price, billing cycle and description. The app's upgrade window and our website's plans page both read it, so a change in the admin panel updates both with no new app version.
Lock paid modules on every door
Our Shopify integration shipped in June 2026 without a plan lock. For three months it was free to every company on the platform, and nobody noticed because it worked perfectly. Broken features get reported. Free features do not. The integration did have a guard, but it only checked the role, "is this person the account owner?" Every account has an owner. A role answers who inside an account may do something. It does not answer whether the account paid for it.
A paid module now needs both checks: the right role and the plan key. The plan check fails closed, meaning the module opens only when the plan explicitly says yes. It also runs on every door into the module: the mobile screen, the web screen, the sync function, the incoming-orders hook and the scheduled job. One door always stays open, because a customer can switch the integration off even when it is locked.
Notice the difference from plan features. Our general check for features included in a plan fails open: if the feature list fails to load for a moment, the feature stays available, because a network glitch should never lock out a paying customer. For a separately paid module, "open when unsure" means only the customers who ask ever pay.
The last two lines matter. Before you close a door, you need to know who is standing behind it.
Copy the reason, not the number
When we designed the field sales add-on, my assistant suggested a minimum number of reps per customer, because a well-known American field-sales app has one. I asked why a minimum exists. Their reason is to cover the fixed cost of taking on each new customer. Ours is covered by the base plan, and one extra rep costs almost nothing, so a minimum would have turned away small companies for no gain. When you study competitors, copy the reason behind a price, never only the number.
Trials and free plans
Define the trial length in one place. We once had it written in two signup paths and in several texts across the app and blog, including hidden data that search engines show. Changing a trial means changing all of them together. For a free plan, the principle I would keep is this: lock what grows their business, never lock what corrects it. If a free company cannot record a return, it will delete the original invoice or enter a negative sale, and your lock will have pushed customers to falsify their own books.
For Western customers, Stripe handles many currencies and can calculate tax, and Lemon Squeezy sells on your behalf and handles sales tax and VAT. Check their current fees. Chapter 9 of the book covers the full plan design.
Key takeaways
- The price on your website is not the price customers pay, so store and read the real one.
- Charge for what grows with the customer: users, branches, reps.
- A subscription is a set of lines with a calculated total, never one typed number.
- Paid modules need a plan lock on every door and must stay closed when unsure.
- In a free plan, lock what grows the business, never what corrects it.
Frequently asked questions
How should I structure SaaS pricing plans?
Use a few plans that differ mainly by something that grows with the customer, like users or branches. Add big modules as separate add-ons, offer a trial, and keep every price in your database so changes need no new app version.
Should a SaaS use per-user pricing?
Per-user pricing works when value grows with headcount. Before copying a competitor's rules, such as a minimum number of seats, find out why they exist and whether that reason applies to your costs.
How do I stop customers using paid features for free?
Check the plan on every way into the feature, not only the screen, and make the check fail closed. A role check alone is not enough, because it shows who may use a feature, not whether the company paid for it.