Pricing·Advanced·12 min·Updated 2026-10-13
Renewal at list price: when the pricing procedure ignores your Renew lines
A native renewal coming out at full list price — no bundle discount, no included components, no indexation. Four causes stacked inside the procedure, and the tool that makes them visible.
How claims are labelled
Scroll the diagram sideways
The rule that keeps a catalog maintainable: a decision table only when there is a condition or a tier. A flat price belongs on the PricebookEntry. Decision tables added by reflex are what fills a procedure up to its element ceiling.
And the procedure that runs is the compiled _Auto version, not the source you edit.
Nobody would catch this on a demo. On a real book of business, it is a wrong invoice on every anniversary date.
The symptom
A bundle sold as 5 licences at 3,600, with a 10% bundle discount (3,240 net) and a dozen included components at 0. We put 1.58% indexation on the asset and clicked Renew.
| Line | Original sale | Renewal produced | Expected |
|---|---|---|---|
| Licences ×5 | 16,200 | 18,000 | 16,455.96 |
| Included components | 0 | 4,252 | 0 |
| Total | 16,200 | 22,252 | 16,455.96 |
The indexation rate is on the line. The price ignores it, exactly as it ignores everything else. Terrain
First mistake: fixing the wrong procedure
We had a procedure plan active on Quote, pointing at a custom procedure. Every fix went into it. Five versions later, nothing had moved.
The procedure that prices a quote through the API — and therefore renewals — was not the plan’s. It was the pricing recipe’s default procedure. The plan was not on that path at all. Terrain The exact scope of procedure plans by entry point remains À vérifier
Two traps kept this invisible for a long time.
- A new version carrying the same start date as the previous one is not selected. If you clone a version to edit it, move its start date forward.
- The engine caches the procedure for a minute or two after a deployment. A test run immediately after runs on the old version. Run it in a loop until you see the change.
The habit to build: mark every version. Change a step’s label —
Get base prices from price book V7 — and check that it shows up at runtime.
Without that marker you do not know what you are testing. Recommandé
The tool that changes everything: the pricing waterfall
Pricing logs only tell you a line succeeded or failed, with no message. The waterfall gives you every step that ran, with its inputs and outputs.
The execution identifier it expects is the part before the _ in the line
execution’s type key, not the global key. With the wrong one, the API answers “check your Price
Waterfall settings”, which sends you down a false trail. Terrain
That waterfall revealed all four causes below, in a single read.
Four causes, stacked
Lines created by the renewal arrive with two peculiarities: they are marked as priced from
the last transaction, and their derived pricing attribute is empty. A fresh
sale line has that attribute set to false. Terrain
1. The lines fail silently
Several groups in the standard procedure filter on “derived attribute is not null AND equals false”. An empty value passes neither. Those lines skip the net price calculation and end in failure. The engine then keeps the list price, with no error message.
Fix: “derived attribute is null OR equals false” in those groups.
2. A “last transaction” step overwrites the result
The last-transaction branch ends by assigning the input unit price to the net price. It runs after discounts and indexation, and resets the net price to the original unit price before discount. In the waterfall you can watch the indexation compute the right amount, then this step erase it.
Fix: exclude Renew lines from that branch.
3. Discounts exclude renewals
Bundle discount, volume discounts, amount and percentage discounts, attribute-based pricing: every group carries a filter that excludes last-transaction lines. For an amendment that is defensible. For a renewal it removes the bundle discount and the zero price on included components.
Fix: add an exception for the Renew type on those filters. Recommandé We chose to renew at the current list price, reapply the bundle discount, then index. If your policy is to start from the net actually paid, that is a different piece of work.
4. Indexation has nowhere to land
The native price revision step requires a revision policy on the line and the last-transaction branch. With no policy, it does nothing. We added a formula-based pricing step: the net price, plus the net price multiplied by the line’s indexation rate, filtered on a non-null rate and a positive quantity, and placed after the discounts.
The percentage stored as 1.58 arrives in the context as 0.0158. Terrain
What we ruled out
- An Apex hook in the procedure plan. We had already measured it: the following pricing section re-reads the records and overwrites whatever the hook wrote. And the plan was not even on the path.
- Forcing the price through the API. Setting a unit price different from the list price does trigger the full calculation — even 3,600.01 instead of 3,600. A price equal to the list price is ignored, which is precisely the normal case for a renewal. A crutch, not a solution.
- Writing the price on the line by DML. Refused as soon as the line has a detail record: “You can’t edit the Sales Price because the Quote Line Item has related Quote Line Detail records”.
The result
A renewal created from the button, with no manual step: 16,455.96 — that is 3,600, less 10% bundle discount, plus 1.58% indexation, with included components at 0.
Two checks before production: a fresh sale still prices the same, and a negative amendment keeps its prorated amount.
What it costs
- One more procedure version. With filters that depart from the standard. Every Salesforce release upgrade means re-reading those groups.
- Eight modified filters. Whose logic has to be documented — otherwise the next administrator will “fix” them back.
- A deliberate business choice: The renewal restarts from the current list price. A list price increase therefore stacks on top of the indexation.
Salesforce components
Select one to open its detail.
What this is based on
- Org running Advanced Transaction Detail Line Pricing, with the line mapping step in place. Without it, negative amendment lines come out at 0: that is the subject of the negative amendment at zero.
- The “empty derived attribute on Renew lines” behaviour and version selection by start date are observed, not documented. They may change with a release.
- Which procedure is chosen by entry point — API, screen, plan — remains to be verified on your own org. Mark your versions before concluding anything.
- Observed on an org at Summer ’26 / Winter ’27.