CPQ & quote-to-cash
How quotes, price books, approvals, and billing connect into one revenue chain, plus the config choices that decide whether a signed deal actually invoices correctly.
The most expensive quote-to-cash bug I ever chased was a discount that approved itself. A rep built a quote, applied a 45% discount, and the approval routing was keyed to a discount-percent field that the pricing logic recalculated after the approval check ran. By the time the field settled, the approval had already fired against the pre-recalc value of 12%, cleared instantly, and the deal closed. Finance found it at quarter-end when the invoice went out at a margin the CFO had never signed off on. The quote said one thing, the order said another, and the billing system faithfully billed the wrong one. Quote-to-cash is a chain, and a chain fails at whichever link you forgot to test.
Quote-to-cash is where the CRM stops being a system of record and becomes a system of money. Everything upstream (leads, opportunities, forecasts) is an estimate. The quote is the first artifact a customer signs, the order is what you are contractually obligated to deliver, and the invoice is what hits their bank account. Each handoff between those is a place where data can silently transform, and unlike a bad forecast, a bad invoice has a customer on the other end.
The chain: opportunity to quote to order to invoice
Configure-Price-Quote sits on top of the opportunity and produces a quote made of quote line items, each drawn from a product in a price book at a governed price. When the customer signs, the quote becomes an order (or a subscription and its order lines), and the order is what billing reads to generate invoices. Revenue recognition then reads the order and the delivery schedule to book revenue over time. The discipline that makes this work is that each stage reads from the one before it and nobody edits a value that a downstream stage already committed.
Price books are the single source of list price
The price book is where list price lives, and it should be the only place. One product, one entry per price book, one list price. Currencies and regional pricing get separate price book entries, not a hard-coded number on a quote line. The moment a rep can type a list price freely into a quote, you have lost the ability to answer “what is our list price for this SKU,” because the answer becomes “whatever the last rep typed.” Governed pricing means the quote pulls list from the price book and the rep can only move the discount, within limits the system enforces.
Discounting is the pressure point. A quote line carries list price, discount, and net price, and the relationship between them has to be computed in one place and one order. The bug I opened with came from two systems both deciding the discount: a formula and an approval rule, running in an order nobody had pinned down. Compute net price once, deterministically, and route approvals off the final computed value, never off an intermediate one.
| Layer | Owns | Rep can change |
|---|---|---|
| Product | SKU, name, product family | No |
| Price book entry | List price per product per currency | No |
| Quote line | Quantity, discount within limits | Quantity and discount only |
| Approval rule | Whether a discount is allowed | No, it gates |
| Order line | Frozen copy of the signed quote line | No, read-only after order |
Approvals: gate on the final value, log the decision
Approval routing is where quote-to-cash meets governance. The rule is simple to state and easy to get wrong: gate on the final, computed net value, evaluate the rule after all pricing logic has settled, and store an immutable record of who approved what and when. A discount over a threshold routes to a manager; a term or a non-standard clause routes to deal desk or legal. The failure modes are all timing: approving against a value that later changes, or letting a rep edit the quote after approval without re-triggering it.
Here is the shape of the guard I put on the quote object so a post-approval edit cannot slip through:
// Block editing approval-relevant fields once a quote is Approved,
// unless the editor resets status to Draft (which re-triggers approval).
AND(
ISPICKVAL( PRIORVALUE( Approval_Status__c ), "Approved" ),
ISPICKVAL( Approval_Status__c, "Approved" ),
OR(
ISCHANGED( Discount_Percent__c ),
ISCHANGED( Net_Total__c ),
ISCHANGED( Contract_Term_Months__c )
)
)
View as table
| Stage | Value |
|---|---|
| Quotes built | 200 |
| Routed to approval | 200 |
| Cleared in 24h | 90 |
| Signed in period | 128 |
Build it or buy it: native vs a CPQ platform
Not every team needs a heavyweight CPQ platform. If your catalog is small, your pricing is flat, and your discounts are simple, native quoting plus a few validation rules and an approval process will carry you for a long time and cost nothing extra. You reach for a dedicated CPQ platform (Salesforce Revenue Cloud, Nue, DealHub, and similar) when the pricing gets genuinely hard: usage-based or tiered pricing, ramped subscriptions, bundles and co-terming, multi-year schedules, and revenue recognition that finance needs to be automated rather than reconstructed in a spreadsheet.
| Native quoting | Dedicated CPQ platform | |
|---|---|---|
| Catalog size | Handful of SKUs, flat pricing | Large catalog, bundles, tiers, usage |
| Subscriptions and ramps | Manual or unsupported | Native ramp schedules and co-terming |
| Approval complexity | A few threshold rules | Multi-dimension, deal-desk workflows |
| Billing and rev-rec | Handed to finance manually | Automated order-to-invoice and schedules |
| Best when | Simple, high-margin, low variance | Complex pricing that a formula cannot hold |
- 1
1. Govern list price in the price book
One product, one entry per currency, one list price. Reps move discount, never list. If a rep can type list price, you have no list price.
- 2
2. Compute net price once, deterministically
List, discount, and net are related in one place and one order of operations. No two systems both deciding the discount.
- 3
3. Gate approvals on the final value
Evaluate approval rules after all pricing settles, route on the computed net, and re-trigger on any approval-relevant change.
- 4
4. Freeze the quote on signature
The order inherits a read-only copy of the signed quote lines. Nobody edits a value a downstream stage already committed.
- 5
5. Let billing read the order, not the quote
The invoice generates from the order and its schedule, so what the customer pays matches what they signed, every time.
Quote-to-cash is a chain from an estimate to a bank transfer, and the whole job is making sure no link silently rewrites the last one. Govern list price in the price book so there is one answer. Compute net price deterministically so approvals gate on a value that will not move. Freeze the quote on signature so the order and the invoice inherit exactly what the customer signed. Reach for a CPQ platform when ramps, bundles, and usage pricing exceed what a validation rule can hold, and not a SKU before. Do that and the invoice matches the quote every time, which is the only quote-to-cash outcome the customer ever actually sees.
Keep reading
All guides →Object & data model
How the standard objects, record types, and custom fields fit together, plus the grain rules and relationship choices that decide whether reporting ever ties out.
ArchitectAutomation architecture
How flows, triggers, and validation rules coexist without fighting, plus the order-of-execution and consolidation rules that keep automation from eating itself.
ArchitectIntegrations & data flow
How systems sync without corrupting each other, plus the ownership, idempotency, and error-handling rules that keep a two-way integration from overwriting the truth every fifteen minutes.