The Salesforce CPQ Deal Lifecycle, End to End
A quote is not a static document — it's a state machine. Here's how a deal actually moves from draft to revenue in a production CPQ org, and where the automation has to live.
Configure-Price-Quote looks like a pricing tool. In practice it's a workflow engine wrapped around the Quote object, and the value lives in the transitions: who can discount how much, when a credit check fires, what happens the instant a deal goes Closed Won. Miss a transition and revenue either leaks or stalls.
Here's the lifecycle I've implemented, stage by stage.
Stage 1 — Configuration & pricing
The rep builds the quote in the Quote Line Editor. Product Rules, Price Rules, and Discount Schedules do the heavy lifting declaratively. The engineering work here is mostly guardrails: validation that blocks invalid bundles, and Price Rules that inject calculated values (e.g. ramp pricing, proration) without the rep touching them.
Rule of thumb: if it's deterministic pricing math, it belongs in a Price Rule, not Apex. Reserve Apex (a Quote Calculator Plugin) for logic the declarative engine genuinely can't express.
Stage 2 — Discount routing & approvals
Every org has discount thresholds: a rep can self-approve to 10%, a manager to 25%, a VP beyond. The clean implementation drives this from the quote's effective discount, not from a pile of nested IF blocks.
- Compute the max line discount (or blended deal discount) on the Quote.
- Route through Advanced Approvals (or core Approval Processes) with rules keyed on that field.
- Make approval tiers data-driven — Custom Metadata mapping discount bands to approver roles — so finance can re-tier without a deploy.
// Quote-level rollup that approvals key off of
public static Decimal maxLineDiscount(List<SBQQ__QuoteLine__c> lines) {
Decimal max = 0;
for (SBQQ__QuoteLine__c l : lines) {
if (l.SBQQ__Discount__c != null && l.SBQQ__Discount__c > max) {
max = l.SBQQ__Discount__c;
}
}
return max;
}
Stage 3 — The credit check (the one everyone forgets)
For new or high-risk customers, you don't want to discover a credit problem at signature. Fire an automated credit check when the opportunity reaches the Proposal stage — far enough along to be real, early enough to course-correct.
Mechanically: a Flow (or trigger) on stage change calls out to the credit/finance system, writes back a status and limit, and either clears the quote to proceed or flags it for manual review. Keep the callout async (Queueable or a Flow + Apex action with a future) so the stage change isn't blocked on an external system.
// Triggered when Opportunity reaches Proposal (75%)
@future(callout=true)
public static void runCreditCheck(Set<Id> oppIds) {
for (Opportunity o : [SELECT Id, AccountId FROM Opportunity WHERE Id IN :oppIds]) {
CreditResponse r = CreditService.check(o.AccountId);
update new Opportunity(
Id = o.Id,
Credit_Status__c = r.status,
Credit_Limit__c = r.limit
);
}
}
Stage 4 — Contract generation
Once approved, the quote drives document generation (DocuSign / Nintex or native). The engineering concern is keeping the generated artifact and the quote data in lockstep — generate from the saved quote, never from unsaved UI state, and lock the quote against edits once a contract is out for signature.
Stage 5 — Closed Won → order completion
The transition that turns a quote into revenue. On Closed Won you typically:
- Generate the Order and Order Products from the primary quote.
- Trigger downstream provisioning / fulfillment (often via integration to ERP).
- Kick off the billing/subscription schedule if you're on a recurring model.
Do this in one bulk-safe handler, not five competing automations. The most common production incident I see in CPQ orgs is a Flow and an Apex trigger both reacting to Closed Won and racing each other. Consolidate the Closed-Won behavior behind a single entry point.
Amendments & the second act
Deals don't end at Closed Won. Amendments, renewals, and co-terms all spin up new quotes against an existing contract. The Quote Line Editor extensions you build for amendment flows are where a lot of the real complexity lives — preserving original pricing, prorating mid-term changes, and keeping the amendment's math consistent with the original order.
The mental model
Stop thinking "quote = form." Think "quote = state machine," where each transition has an owner:
| Transition | Owner |
|---|---|
| Configure / price | Product & Price Rules (declarative) |
| Discount approval | Approval rules + metadata-driven tiers |
| Credit check | Async callout at Proposal stage |
| Contract | Doc-gen from saved quote, quote locked |
| Closed Won | One consolidated order-completion handler |
Get the ownership map right and the org stays maintainable as the sales process inevitably grows new branches.