Skip to content
Taylorz CRM Developers
Esc
↑↓navigate↵open⌘Jpreview
On this page

Commerce and CPQ

The path from a product to a signed number: the policy, the profile that decides how a line is priced, price books, purchase costs, and quote versions.

Every endpoint here needs the cpq module. The flow runs in one direction: the workspace’s policy and profile decide what is possible, price books and purchase costs supply the numbers, and a quote version freezes a result.

The policy comes first

GET /settings/commercial answers the arithmetic every quote obeys. It is one object per workspace, carrying a revision, and nothing in a quote overrides it.

Setting Default What it decides
baseCurrency JPY The currency amounts are reported in
currencies {} Which other currencies are allowed, and on what terms
currencyScale 0 Decimal places on a money amount, 0 to 4. The default matches the default currency
rounding half_up How a computed price is rounded: half_up, half_even, toward_zero, floor, ceil
taxRounding floor The same choice, applied to tax independently
taxCalculation per_rate_total Whether tax is computed per_line or once per rate across the quote
calculationOrder discount_before_tax Whether a discount lands before or after tax
pricesIncludeTax false Whether a catalogue price is tax-inclusive
fiscalYearStartMonth 4 The reporting year’s first month
timezone Asia/Tokyo The zone dates are interpreted in

Changing the policy is a versioned write. PUT takes the revision it was read at and refuses a stale one with settings_stale. Quotes already written keep the policy they were priced under — each version carries a policySnapshot.

The profile decides how a line may be priced

GET /cpq/configuration answers one field, profile, and it decides which of five pricing methods a quote line may use.

Method catalog procurement hybrid Needs a purchase cost
catalog ✓ ✓
cost_plus ✓ ✓ ✓
gross_margin ✓ ✓ ✓
resale ✓ ✓ ✓
manual ✓ ✓

A catalog workspace prices only from its price books. A procurement workspace cannot use catalog at all. Read the profile before offering a method in a user interface; a method the profile does not include is refused rather than ignored.

How each method computes a price

Rates are decimal fractions, not percentages, and every result is rounded with the policy’s rounding.

Method The arithmetic
catalog The price book entry. Nothing is computed
cost_plus cost × (1 + markup)
gross_margin cost ÷ (1 − margin)
resale retailPrice, then × (1 − rate) once per entry in downstreamMargins, which holds one to ten rates
manual The unitPrice given. It also requires a reason of 1 to 500 characters

The three cost-based methods refuse with purchase_cost_required when the cost entry is missing or negative. manual reports no cost and no profit; the others report unitProfit as unitPrice − unitCost.

manual is the escape hatch, and it is recorded as one. The required reason is stored on the line, so a quote priced by hand says why.

Products, price books and agreements

A product is something sellable. A price book is a named list of prices in one currency; prices enter it through POST /price-books/{id}/entries in batches of 1 to 500 rather than one at a time.

A price agreement binds one account to one price book for a period. When several apply to a line, the highest priority wins and the larger minimum quantity breaks a tie. A tie on both is refused with price_agreement_ambiguous rather than resolved arbitrarily — two agreements that disagree are a configuration problem, not a pricing question.

A purchase cost is what the business paid, recorded by POST /purchase-costs and read per product by GET /products/{id}/purchase-costs. A line that prices from one names the entry by costEntryId, so the quote records which historical cost it used rather than today’s.

A quote, its versions and its lines

A quote has a number, an account, optionally an opportunity, and a backing CRM record. It holds no amounts itself — those live on its versions.

A version is one priced state of the quote. It carries currency, subtotal, taxableAmount, tax, discount, total, the cpqProfile and policySnapshot it was priced under, a customerSnapshot, a contentHash, and a state from draft, submitted, approved, rejected, accepted and superseded.

The commerce endpoints report that state and do not set it; what moves a version through it is the approvals side, submitted against the quote’s record. What commerce does control is whether a version is frozen, which is a separate flag from the state.

A version’s lines carry quantity, unit, unitPrice, unitCost, netAmount, discountAmount, taxRate, the pricingMethod used, a priceSnapshot, and the sourcePriceEntryId or sourceCostEntryId the number came from. Two enumerations group them: chargeType is one_time, recurring or milestone, and componentKind is product, hardware, software, service, option or package.

Each line may carry schedules — how its amount is billed over time, with the same three kinds as chargeType, an interval in months, and a milestone label. They are a billing concern rather than a pricing one; the reference has their shape.

Drafts and revisions

Two paths exist, and they are not the same.

POST /quotes creates a quote and freezes its first version. POST /quotes/drafts creates the same thing with that version left unfrozen, which PUT /quotes/{id}/draft then edits in place. A frozen version cannot be edited — quote_version_frozen says to create a revision instead.

POST /quotes/{id}/versions revises a quote by adding a version. It refuses in two ways worth knowing:

  • quote_stale — the revision you sent is not the current one. Reload and try again.
  • quote_draft_open — the latest version is not frozen yet. Finish the draft before revising. A draft and a revision are two ways to change the same quote, and only one can be in flight.
  • quote_approval_pending — an approval is open on the quote. Withdraw it before revising.

POST /quotes/preview prices a quote without creating anything, which is how a user interface shows a total while someone is still typing.

Trying it without a cost history

A procurement or hybrid workspace cannot price a cost_plus line until a purchase cost exists for that product. Record one with POST /purchase-costs first, or use manual with a reason while the cost history is still being loaded.

Was this page helpful?