GTM Operations
Your CPQ Project Is a Pricing-Governance Project Wearing a Config Ticket
A CPQ replatform stalls on the approval matrix and the discount policy, not the field mapping. Here is the governance layer to build first, rung by rung, with the matrix, the routing, and the validation.
· 13 min read
Fourteen months into a CPQ replatform, on the second implementation partner, and the thing still was not live. I got pulled in to figure out why. The kickoff deck blamed product mapping, the bundle logic, the migration of legacy quotes. I asked one question in the first hour: show me the approval matrix the tool is supposed to enforce. Nobody had one. Not a stale one, not a wrong one. It did not exist as a document anyone could point to. The engagement had spent fourteen months building a machine to enforce rules that were still living in five people’s heads and disagreeing with each other.
That is the pattern in almost every stuck CPQ project I have seen. For years the fix for quoting pain had one name: replatform. Rip out the old CPQ, buy the new one, and the discount chaos goes away. It does not. The config is never the hard part. The hard part is that the company never wrote down who can approve a 22% discount, what happens at 35%, and which deals a rep can close without asking anyone. CPQ is a governance system that ships as software. Treat it as a software project and you configure a beautifully modeled void.
Here is the governance layer I build before anyone touches the catalog, and the order I build it in. Five rungs, bottom to top: the discount policy sits at the base, and nothing above it can hold until it does. This ladder is the whole project. Scroll it, then I will show you the artifacts and the math under every rung.
- L5Instrument the spread, review monthly$/qtr
Roll margin-given up by approver role and put it on the monthly deal-desk review. The number that was invisible in the list-to-net spread becomes the one that keeps the matrix honest.
- L4Gate the quote with a validation ruleISPICKVAL
Block the quote from advancing to order when the discount is over the self-serve band and the approval record does not exist. Governance that can be skipped is decoration.
- L3Route from the matrix at runtimelookup
The approval process looks up the band the discount lands in and routes to that role with that SLA clock. Change fiscal-year policy by editing records, not rewiring approvals.
- L2Encode the approval matrix as data5 records
Turn the one-page policy into custom metadata records: band boundaries, approver role, response SLA. The policy becomes machine-readable and edited without a deploy, not a slide nobody can find.
- L1Write the discount policy1 page
Get the CRO and CFO in one room and agree on the floor, the bands, and who owns margin at each tier. One page. If you cannot get this page, the project is not ready to configure, and every hour of config before it is speculative work you will redo.
Locate the stalled project on that ladder. It was trying to build rung four, the enforcement, on top of a missing rung one. No policy, so no matrix; no matrix, so nothing to route on; nothing to route on, so the tool could not be configured no matter how many partners you threw at it. Every rung depends on the one below it, and the whole company had skipped straight to the software.
The two projects hiding inside one CPQ ticket
Every CPQ initiative is two projects stapled together. One is configuration: product catalog, bundle rules, price books, the quote document template. That work is real and bounded, and a competent admin or partner finishes it. The other is governance: the discount policy, the approval matrix, the routing that enforces it, the audit trail that proves it happened. That work has no natural owner, it requires the CRO and the CFO to agree on numbers they have avoided writing down, and it is the reason projects stall.
When a CPQ go-live slips, walk the failure back and it almost always lands on the governance side. The bundle logic is annoying but tractable. The question “can a Regional VP approve 30% or does that go to the CRO” is a political question dressed as a technical one, and until someone answers it, the tool cannot be configured, because the tool’s entire job is to route on that answer.
What ungoverned discounting costs the quarter (rung L1)
Here is the worked example that pulled the fourteen-month project into focus. The team quoted about $8M of ACV in a quarter. Policy, such as it was, said list-minus-12% was the standard floor without escalation. Actual average discount across closed quotes came in at 18%. That six-point gap, applied to $8M, is $480K of margin the company gave away in one quarter because there was no gate between a rep’s optimism and a signed order. That number reconciles to the $480K stat tile at the top of this piece, and it is the reason rung one exists.
That $480K is not a rounding error. It compounds every quarter it goes unmeasured, and it does not show up in any pipeline report, because raw pipeline dollars and bookings both look healthy. The leak lives in the spread between list and net, and nobody was watching the spread. The sales cycle stretching out makes it worse: the average B2B cycle is now 6.5 months, up from 4.9 in 2019 (Ebsta 2024), and the longer a deal sits, the more a rep reaches for discount as the closing lever of first resort.
| The hidden cost | Value | Source |
|---|---|---|
| Quoted ACV in the quarter | $8.0M | worked example |
| Policy discount floor | 12% | worked example |
| Actual average discount | 18% | worked example |
| Margin given away (6 pts of $8M) | $480K | worked example |
| Average B2B sales cycle (pressure to discount) | 6.5 months | Ebsta 2024 |
| Expansion share of new revenue at risk from bad first pricing | 52% | gradient.works 2025 |
That last row matters more than it looks. Expansion is 52% of new revenue for a lot of teams (gradient.works 2025), and the discount you set on the first order becomes the baseline the customer expects at renewal and expansion. Ungoverned discounting is a multi-year annuity you sold at a loss, not a one-quarter margin event. The deal desk operating model exists to stop exactly this leak.
The artifact that unsticks the project: an approval matrix as data (rung L2)
The document the fourteen-month project was missing fits on one page. Discount bands, who approves each band, and how long they have to respond. That is the whole spine. Write it as a table first, because the CRO and CFO need to argue over it in a format they can read, then encode it as data the tool reads at runtime.
| Discount band | Approver | Response SLA | Notes |
|---|---|---|---|
| 0 to 10% | Rep (self-serve) | none | Inside policy, no gate |
| 10 to 20% | Sales Manager | 4 hours | Manager owns margin at this tier |
| 20 to 30% | Regional VP | 8 hours | RVP sees the spread, not the CRO |
| 30 to 40% | VP Sales plus Deal Desk | 24 hours | Two-key rule, deal desk logs rationale |
| 40% and up | CRO | 48 hours | Rare by design, every one reviewed |
The failure mode I keep seeing is that this matrix lives in a slide, so the tool cannot read it and reps cannot find it. Encode it as configuration the CPQ engine reads at runtime. In a Salesforce-based stack that means custom metadata, so the bands are data you edit without a code change, not a hardcoded ladder buried in ten screens:
# Discount_Approval__mdt (custom metadata, one record per band)
- label: "band_0_10"
min_discount: 0.00
max_discount: 0.10
approver_role: "Rep" # self-serve, no submission
sla_hours: 0
- label: "band_10_20"
min_discount: 0.1001
max_discount: 0.20
approver_role: "SalesManager"
sla_hours: 4
- label: "band_20_30"
min_discount: 0.2001
max_discount: 0.30
approver_role: "RegionalVP"
sla_hours: 8
- label: "band_30_40"
min_discount: 0.3001
max_discount: 0.40
approver_role: "VPSales_DealDesk" # two-key
sla_hours: 24
- label: "band_40_plus"
min_discount: 0.4001
max_discount: 1.00
approver_role: "CRO"
sla_hours: 48
Now the routing is a lookup, not a folklore (rung L3). When a quote’s discount crosses a band boundary, the approval process reads the matching record and routes to that role with that SLA. Change the policy next fiscal year and you edit five records, not a code base.
The gate: a quote cannot leave without passing the matrix (rung L4)
The matrix is inert without a gate that blocks the quote from advancing until the required approval exists. This is where most home-grown attempts fail: the routing sends a notification but the rep can still generate the order document anyway. Governance that can be skipped is decoration. Put a validation rule between the quote and submission so an over-policy discount physically cannot progress without the approval record.
In Salesforce that is a validation rule using ISPICKVAL, not an operator against a picklist:
AND(
Discount_Percent__c > 0.10,
ISPICKVAL(Approval_Status__c, "Not Submitted"),
NOT(ISPICKVAL(Approval_Status__c, "Approved"))
)
That rule reads in English as: if the discount is over the self-serve band and the quote has not been submitted for approval, stop. The rep gets a message telling them which approver they need and why. The gate is dumb on purpose. It does not judge the deal, it enforces that the deal went through the ladder the leadership team agreed to.
Once the gate is live, you can finally measure the spread you were blind to (rung L5). This query rolls quotes up by the approver role that touched them, so you see where discount concentrates and whether the matrix is holding:
SELECT
approver_role,
COUNT(*) AS quotes,
ROUND(AVG(discount_pct) * 100, 1) AS avg_discount_pct,
SUM(list_amount - net_amount) AS margin_given
FROM quote_line_rollup
WHERE created_date >= DATEADD('quarter', -1, CURRENT_DATE)
GROUP BY approver_role
ORDER BY margin_given DESC
Run that before the gate exists and the approver_role column is mostly null, which is the whole problem in one result set: nobody approved most of it. Run it after, and the margin-given number becomes a leading indicator you review every month.
What changes when the gate goes live
Here is what happened after we shipped rungs one through four on the stalled project. The discount distribution moved. Toggle the two states below: before governance, the mass of deals sat in the 20-to-30% band because that was the path of least resistance and nobody stopped it. After the gate, deals clustered back inside policy, because the friction of an approval at 25% made reps defend the price or take the 12% they could self-serve.
View as table
| Item | Value |
|---|---|
| 0-10% | 10% |
| 10-20% | 25% |
| 20-30% | 40% |
| 30-40% | 20% |
| 40%+ | 5% |
Average discount fell from 18% to 12.5%. On the same $8M of quarterly quoting that is roughly $440K of margin recovered, from a change that was a one-page table and three configuration objects. The fourteen months of config work was never the blocker. The blocker was the page nobody wrote.
Config as a project vs governance as a project
| CPQ run as a config project | CPQ run as a governance project | |
|---|---|---|
| First artifact built | Product catalog and bundle rules | Discount policy and approval matrix (rung L1) |
| Owner | Admin or implementation partner | RevOps, with CRO and CFO sign-off |
| What blocks go-live | Field mapping edge cases | Nobody has decided who approves 30% |
| Where the matrix lives | A slide, if anywhere | Custom metadata the tool reads at runtime (rung L2) |
| Can the gate be skipped | Yes, notification only | No, validation blocks submission (rung L4) |
| Discount leakage | Invisible, in the list-to-net spread | A monthly leading indicator (rung L5) |
The uncomfortable part
The reason CPQ projects stall on governance and not config is that config is safe to work on. Field mapping never forces a Regional VP to admit they have been approving discounts they had no authority to approve. The matrix does. When you hand leadership a one-page ladder and ask them to sign it, you are not asking a technical question, you are asking them to give up discretion they enjoyed and to make the spread visible. That is the friction, and it is why the work gets displaced onto the catalog every single time.
So if your CPQ project is behind, do not ask the partner to move faster on config. Ask who has signed the discount policy. If the answer is nobody, you found your fourteen months. Climb the ladder in order: write the one page, encode the five records, route from the matrix, ship the gate, and put the leakage query on the monthly review. The tool was never the bottleneck. The decision was. For the wider operating model this gate plugs into, the deal desk guide has the thresholds, the repository, and the review cadence that turn one gate into a system.
Keep reading
One email. Every week.
One email a week: an operating problem I solved or botched, with the model, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.
The newsletter opens soon.
Connect a provider in src/config.ts