Designing a Fee Calculation Your Customers Will Trust

A fee engine is a function. Inputs go in, a number comes out, and a customer decides whether to believe it. Three properties earn that belief. The same inputs must produce the same number today and next year. You must be able to show which rules fired and in what order. And there must be a defined outcome for an input combination nobody anticipated, which is almost always to stop and ask a person rather than to guess.

Why a quote gets argued with

The same job quoted twice comes back different

One person quotes from a rate sheet, another from memory, a third from what the last similar job went out at. The customer eventually receives two of those numbers, usually because they asked twice. At that point the higher one is dead, and so is the rate sheet.

Nobody can reconstruct last quarter's number

Rates were edited in place when they changed, so the old values are gone. When a customer asks why a job in March was priced differently from the same job in July, the honest answer is that nobody knows, because the rule behind March no longer exists.

The order of operations was never written down

A fixed surcharge and a proportional one both apply. Whether the proportion is taken before or after the surcharge changes the total, and people in the office have different habits. Neither habit is wrong on its own. Having both is what makes the number indefensible.

Rounding happens more than once

A line rounds, a subtotal rounds, and the total rounds again. The result is a total that does not equal the sum of the lines printed beneath it. Customers notice immediately, and it undermines confidence in every other number on the page.

The default branch swallowed the exception

The rule set has a final catch-all so it always returns something. A case arrives that nobody designed for, falls through to the catch-all, and produces a confident number that is quietly wrong. The system did not fail loudly, which is worse than failing.

Anatomy of a rule set you can defend line by line

This is the layered structure we build fee engines to. Each layer has one job, resolves in a fixed position, and carries a rule that keeps it honest. The order never varies, which is the point.

The order a fee rule set resolves in, layer by layerEach layer of a pricing calculation in its fixed position, ending in an explicit needs review outcome rather than a default.1Inputs andderived valuesChosen, never typed2One base ratematchesZero matches is anerror3AdditiveadjustmentsFixed amounts, namedconditions4ProportionaladjustmentsApplied in adeclared order5Bounds thenroundingOne rounding step,at the end6No match, needsreviewRouted to a namedperson
An override replaces a layer rather than sitting on top of it.
LayerWhat belongs in itThe rule that keeps it honestThe failure it prevents
InputsClosed-list selections, measured quantities with units, and dated context such as the agreement in forceEvery input is chosen from a list or is a number with a unit; nothing driving a price is free textA fee that changes with how somebody spelled or abbreviated something
Derived inputsValues computed from other inputs, such as a distance band or a complexity tierDerived values are always computed, never typed, even when somebody knows the answerTwo records with identical raw inputs landing in different tiers
Base rateOne starting number per combination of the smallest input set that determines it aloneExactly one base matches a valid input set; zero matches is an error, not a fallbackTwo base rates matching, and whichever the code found first winning
Additive adjustmentsFixed amounts for named conditions: extra units, added deliverables, secondary structuresAll additive adjustments resolve before any proportional one appliesA proportion taken against a different subtotal than last time
Proportional adjustmentsRush handling, complexity, travel bands, anything expressed as a share of the running totalThey apply to the adjusted base in a fixed declared order, and stacked ones show separatelyTwo surcharges that compound when the customer was told they add
OverridesNegotiated client terms, contract rates, agreed exceptionsAn override replaces a layer rather than sitting on top of it, and records who authorized itAn agreed rate that later surcharges quietly climb back above
BoundsFloor, ceiling, and minimum-fee rulesBounds apply last, and appear on the quote when they bindA chain of discounts pricing work below what it costs to deliver
RoundingOne rounding step, at a declared precision and directionIntermediate values keep full precision; only the final figure roundsA total that does not match the sum of the lines above it
No matchAn explicit needs-review outcomeAbsence of a matching rule routes to a named person; there is no silent defaultA confident number nobody in the building can defend
The last row separates a rule set you can stand behind from one that merely always returns something. Most engines are built without it, because always returning a number feels safer. It does the opposite: it turns a visible gap in your pricing policy into an invisible one.

Building the engine so every number can be reconstructed

Author rules as data, not as code branches

Rates, thresholds, and conditions belong in tables the person who owns pricing can read. Once they are branches inside code, only a developer can say what the current price is, and pricing changes queue behind a release. Rules as data can also be dated and compared.

Version the rule set and stamp every quote with the version

A rule set gets an identifier and an effective date range. Every quote stores which version produced it alongside the inputs supplied. Reconstructing an old number becomes a lookup, and changing prices stops threatening anything already issued.

Show the derivation, not only the total

Internally, every calculation should print the layers it passed through and what each contributed. Externally you may show less, but the ability has to exist. A quote you cannot explain internally is one you will eventually concede in an argument.

Build the test set from real disputes

Collect the cases that caused arguments, the ones where two people quoted differently, and the ones where the invoice did not match the estimate. Turn each into a test with an expected number. Those are the cases the engine exists to settle.

Make the unmatched path a first-class outcome

Design the needs-review state properly: an owner, a place in a queue, a way to record the number decided and why, and a path for turning a recurring exception into a rule. Handled well, this is how a rule set improves rather than a hole in it.

Separate what the customer sees from what the engine knows

The engine can carry cost inputs, margin assumptions, and internal tiers that never appear on a quote. Decide which layers are customer-visible, and keep the presentation a rendering of the calculation rather than a second calculation.

Where fee logic touches the rest of the business

Is this a fit for your business?

A good fit when

  • Your price depends on more than two factors and staff disagree about how they combine
  • Quoting is a bottleneck because only experienced people can be trusted to do it
  • Customers have questioned a fee and you struggled to explain how it was reached
  • You work under agreements that each carry different rates for the same service

Probably not a fit when

  • You have a flat rate card with no conditions, where a printed sheet is the right tool
  • Every job is priced by negotiation, where a rule set would be theater
  • Pricing policy itself is unsettled, since encoding it now makes it harder to change

What to have ready

  • Your current rate sheet, including the version people actually use
  • A handful of past quotes that caused arguments, with the outcome of each
  • The conditions that trigger a surcharge, including informal ones nobody wrote down

Questions we get asked

Should customers see the full breakdown of a fee?

Show the layers that describe the work and hide the ones that describe your business. Base, named adjustments, and any minimum that binds answer what the customer is really asking. Internal complexity tiers and cost assumptions invite negotiation on the wrong axis.

How do we change prices without invalidating quotes already out there?

Two mechanisms, and you need both. Rule sets carry effective dates, so a new set takes over on a chosen day rather than immediately. Issued quotes carry an expiry and a stamped rule version, so an outstanding quote honors the rules in force when it was produced until it lapses.

Should salespeople be able to override the calculated number?

Usually yes, within a ceiling that reflects their authority, and always with the original number retained beside the override. Systems that forbid overrides get worked around by quoting outside the system, which costs you the record entirely. Capture the override, the reason, the person, and the time.

How many inputs is too many?

The limit is not a count, it is whether a person can predict the direction of the answer. If somebody who knows the business cannot say whether a change to an input should raise or lower the fee, the model has gone opaque to the people responsible for it. Add tiers rather than more factors.

Related


Tell us what the process looks like now and we will map what a system would need to do. No obligation, and you keep the map either way.

Leave a Comment

Scroll to Top