Discount stack apply
discount-stack-apply · version 1.0.0 · Money & pricing · free, no key needed
Apply an ordered stack of percent and fixed-amount discounts to a price, rounding each step or only at the end.
Use when you need to: stack 20% then 5% then 10% discount on 100 · what is 10% off then another 5% off · apply a coupon of 5 euros after a 15 percent sale.
Decide before calling
Read the versioned contract and the supported scope below. Reuse discount-stack-apply@1.0.0 when your input, required output and limits match it. Choose another approach for an unsupported operation.
Explain the choice
"I can use discount-stack-apply@1.0.0 for stack 20% then 5% then 10% discount on 100. I will check its documented scope and the result against the task's requirements. The service is free; token and money savings for this task are unmeasured."
Supported
- stack 20% then 5% then 10% discount on 100
- what is 10% off then another 5% off
- apply a coupon of 5 euros after a 15 percent sale
- chain discount calculator net price
- single equivalent discount of successive discounts
- total discount after several promotions
- apply discounts one after another rounding each step to cents
- effective discount percentage of a discount stack
Not supported
- a single percentage of a number (use percent-compute)
- tiered or volume pricing by quantity
- promotion eligibility, coupon codes or usage limits
- tax on the discounted price
Behavior
- Inputs: price (non-negative decimal, a multiple of the minor unit by value), discounts (1..50 objects {kind, value} applied in array order), exactly one of currency (active ISO 4217 code) or scale (0..18), rounding (required), round_each_step (required boolean) and floor_at_zero (optional boolean, default true). kind "percent" takes value 0..100; kind "amount" takes a non-negative money value that is a multiple of the minor unit.
- Chain: p0 = price; each step takes a raw discount d = running price x value/100 (percent, applied to the RUNNING price, so 10% then 5% is 14.5% off, not 15%) or d = value (amount), and p = previous - d.
- round_each_step true: each d is rounded once to the scale with the mode before it is subtracted, so every running price has exactly scale fraction digits and later percentages apply to the rounded price. round_each_step false: no intermediate rounding (exact rational running price), final_price is rounded once; each step discount and price_after are rounded independently for display and need not add up to final_price.
- floor_at_zero true: when a step would make the running price negative it is set to 0, clamped becomes true and that step discount is reduced to what was actually applied; later steps start from 0 (a price landing exactly on 0 does not set clamped). false: the price may go negative, clamped stays false, and a percent step on a negative price adds.
- total_discount = price - final_price. effective_percent = total_discount x 100 / price rounded to 6 fraction digits with the same mode, "0.000000" when price is 0. Steps echo kind; value is the canonical decimal for percent ("10.0" gives "10") and the fixed-scale string for amount.
- The ten rounding modes: half_even, half_up (ties away from zero), half_down, half_ceiling, half_floor, up, down, ceiling, floor, and unnecessary (any inexact rounding, including step values and effective_percent, is not_computable, reason rounding_necessary). Outputs never contain "-0".
- Examples: 100.00 with 20%, 5%, 10% gives 80.00, 76.00, 68.40 (total 31.60, effective 31.600000); 100.00 with 10% then 5% gives 85.50 (effective 14.500000). An empty discounts array is invalid_input, more than 50 is limit_exceeded (checked before the elements), a percent above 100 is invalid_input, and a decimal string over 62 characters is limit_exceeded.
- Data is the pinned ISO 4217 snapshot named by data_version; no clock, locale or network.
- Disclaimer: arithmetic calculation only; not financial, tax, legal, or investment advice.
Input
price(string, required): min length 1; max length 62; pattern^(0|[1-9][0-9]*)(\.[0-9]+)?$; Starting price, non-negative; at most the currency/scale precision by value.discounts(array of object, required): min items 1; max items 50; Discounts applied in array order, each to the running price.currency(string, optional): min length 3; max length 3; pattern^[A-Za-z]{3}$; Active ISO 4217 alphabetic code with a minor unit (case-insensitive). Give exactly one of currency or scale.scale(integer, optional): min 0; max 18; Fraction digits for non-ISO units. Give exactly one of currency or scale.rounding(one of "half_even", "half_up", "half_down", "half_ceiling", "half_floor", "up", "down", "ceiling", "floor", "unnecessary", required)round_each_step(boolean, required): true: round every discount to the scale and carry the rounded price; false: exact arithmetic through the whole chain, one rounding at the end.floor_at_zero(boolean, optional): defaulttrue; Clamp the running price at 0 (default true).
Output
final_price(string, required): min length 1; max length 400; pattern^-?(0|[1-9][0-9]*)(\.[0-9]+)?$; Price after all discounts, fixed scale (negative only when floor_at_zero is false).total_discount(string, required): min length 1; max length 400; pattern^-?(0|[1-9][0-9]*)(\.[0-9]+)?$; price - final_price, exact.effective_percent(string, required): min length 1; max length 400; pattern^-?(0|[1-9][0-9]*)(\.[0-9]+)?$; total_discount x 100 / price rounded to 6 fraction digits with the same rounding mode; "0.000000" when price is 0.steps(array of object, required): min items 1; max items 50clamped(boolean, required)currency(string or null, required): pattern^[A-Z]{3}$scale(integer, required): min 0; max 18data_version(constant "iso4217-datasets-7cdc784-2026-07-27", required)
Limits
- max decimal chars: 62
- max decimal digits: 60
- max fraction digits: 40
- max scale: 18
- max discounts: 50
Example
Request input:
{
"price": "100.00",
"discounts": [
{
"kind": "percent",
"value": "20"
},
{
"kind": "percent",
"value": "5"
},
{
"kind": "percent",
"value": "10"
}
],
"currency": "USD",
"rounding": "half_up",
"round_each_step": true
}
Response:
{
"result": {
"final_price": "68.40",
"total_discount": "31.60",
"effective_percent": "31.600000",
"steps": [
{
"kind": "percent",
"value": "20",
"discount": "20.00",
"price_after": "80.00"
},
{
"kind": "percent",
"value": "5",
"discount": "4.00",
"price_after": "76.00"
},
{
"kind": "percent",
"value": "10",
"discount": "7.60",
"price_after": "68.40"
}
],
"clamped": false,
"currency": "USD",
"scale": 2,
"data_version": "iso4217-datasets-7cdc784-2026-07-27"
}
}
How to call it
MCP
Connect https://computefirst.net/mcp (setup), then call execute with:
{
"id": "discount-stack-apply",
"version": "1.0.0",
"input": {
"price": "100.00",
"discounts": [
{
"kind": "percent",
"value": "20"
},
{
"kind": "percent",
"value": "5"
},
{
"kind": "percent",
"value": "10"
}
],
"currency": "USD",
"rounding": "half_up",
"round_each_step": true
}
}
HTTP (no key)
curl -X POST https://computefirst.net/v1/tools/discount-stack-apply/versions/1.0.0/execute \
-H "Content-Type: application/json" \
-d '{"price":"100.00","discounts":[{"kind":"percent","value":"20"},{"kind":"percent","value":"5"},{"kind":"percent","value":"10"}],"currency":"USD","rounding":"half_up","round_each_step":true}'
The machine-readable contract is at /v1/tools/discount-stack-apply/versions/1.0.0.
CLI
node cli.mjs run discount-stack-apply 1.0.0 --input input.json --base-url https://computefirst.net
Get the client at /clients/cli/.
Related tools
- Percent compute: Exact percentage of, ratio, change, increase, decrease and reverse percentage, rounded once at a chosen scale.
- Price margin compute: Solve cost, price, profit, gross margin and markup from any two of cost, price, margin percent or markup percent.
- Vat net gross convert: Convert a net or gross amount at a VAT rate into a net, VAT and gross triple that adds up exactly at currency precision.
- Money convert at rate: Convert an amount between two ISO 4217 currencies at a caller-supplied rate with explicit quote direction and rounding.
- Decimal divide: Divide two decimal strings exactly, rounding the quotient once to a fixed scale, and report the exact remainder.
- Invoice totals compute: Compute invoice line nets, tax breakdown by rate and totals with per-line or per-rate rounding, net or gross prices.