← All posts
Apr 22, 202610 min read

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.

CPQSales CloudFlows

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:

TransitionOwner
Configure / priceProduct & Price Rules (declarative)
Discount approvalApproval rules + metadata-driven tiers
Credit checkAsync callout at Proposal stage
ContractDoc-gen from saved quote, quote locked
Closed WonOne consolidated order-completion handler

Get the ownership map right and the org stays maintainable as the sales process inevitably grows new branches.