Documentation menu

Discounts, tiers and price ranges

PRODUCT / 0.2.0-alpha.1WEBSITE HANDBOOK · IMPLEMENTATION-CHECKED
On this page

A percentage needs a base, a tier needs a boundary, and a range needs a meaning. This guide works through those choices using the Cleaning and Website design templates and a separate graduated-mileage example.

A cleaning quote with two modifiers

Use the Residential cleaning template with three bedrooms, two bathrooms, 1,000 square feet, oven cleaning, no interior windows, a deep clean and weekly frequency.

ChargeAmount
Visit and supplies$60.00
3 bedrooms × $18$54.00
2 bathrooms × $25$50.00
1,000 square feet × $0.03$30.00
Oven$35.00
Subtotal$229.00

The deep-clean rule adds 50% using running_total: $114.50. The running total is now $343.50. The weekly discount then subtracts 15% of that amount: $51.525, rounded to $51.53. The final total is $291.97.

The discount follows the deep-clean adjustment, so it discounts that adjustment too. If its basis were subtotal, it would subtract $34.35 instead and produce $309.15. Neither interpretation is inherently correct; choose the one your business intends and test it.

Compare percentage bases

Suppose the subtotal is $100 and two rules add 10% and 20%:

ConfigurationFirst adjustmentSecond adjustmentTotal
Both use subtotal$10$20$130
Both use running total$10$22$132

subtotal means accumulated charge rules before the percentage; it does not include prior percentage adjustments. running_total also includes earlier adjustments. Place all relevant charges before the percentage and use labels that communicate the business meaning.

A negative percentage represents a discount. The schema rejects percentages below -100, and the final price cannot become negative.

Graduated tiers are cumulative

Consider a separate mileage rule: the first 10 miles cost $2 each, the next 40 cost $1.60 each and additional miles cost $1.30 each. The portable rule fragment is:

Examplejson
{
  "id": "graduated_distance",
  "label": "Graduated mileage",
  "type": "tiered",
  "field": "distance",
  "tiers": [
    { "upTo": 10, "rateMinor": 200 },
    { "upTo": 50, "rateMinor": 160 },
    { "upTo": null, "rateMinor": 130 }
  ]
}

For 51 miles, the amount is 10 × 200 + 40 × 160 + 1 × 130 = 8530, or $85.30. It is not 51 × $1.30. upTo is the cumulative upper boundary, and the final tier must be open-ended.

Test 0, 10, 10.5, 50 and 51 miles. At 10.5, only the extra half-mile uses the second rate. Boundary cases catch confusion between a tier width and a cumulative boundary.

A website quote with a range

The Website design template combines a chosen package, a price for every page, optional functionality and a rush percentage. Package pricing does not include a free-page allowance.

Choose Launch, five pages, no store, no booking integration, no copywriting and no priority delivery:

Exampletext
Launch package        $1,200
5 pages × $180          $900
Total                $2,100
Range              $1,890 – $2,520

The template range is 10% below and 20% above the total. With priority delivery, the 25% running-total adjustment produces $2,625, with a range of $2,362.50–$3,150.

The “Booking integration” and “Online store” choices price agency work. They do not turn OpenQuoteStack into a booking or payment system.

Bounds and ranges serve different purposes

Minimum and maximum alter the final quoted total and appear as adjustments. A range describes uncertainty around the bounded total and does not change it. Its endpoints can extend beyond a configured minimum or maximum.

If your contractual minimum must also be the lowest displayed endpoint, the current range semantics do not enforce that requirement. Adjust the estimator's presentation or wait for a separately designed feature; do not assume bounds clamp the range.

Explain why the range exists, such as discovery work or property conditions. A range is not a statistical confidence interval unless your own pricing process gives it that meaning.