---
title: Commerce and CPQ
description: "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`](/reference/commerce/get-api-v1-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`](/reference/commerce/put-api-v1-settings-commercial) 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`](/reference/commerce/get-api-v1-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`](/reference/commerce/post-api-v1-price-books-by-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`](/reference/commerce/post-api-v1-purchase-costs) and read per product by [`GET /products/{id}/purchase-costs`](/reference/commerce/get-api-v1-products-by-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](/guides/concepts/permissions) 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](/reference) has their shape.

## Drafts and revisions

Two paths exist, and they are not the same.

[`POST /quotes`](/reference/commerce/post-api-v1-quotes) creates a quote and **freezes** its first version. [`POST /quotes/drafts`](/reference/commerce/post-api-v1-quotes-drafts) creates the same thing with that version left unfrozen, which [`PUT /quotes/{id}/draft`](/reference/commerce/put-api-v1-quotes-by-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`](/reference/commerce/post-api-v1-quotes-by-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`](/reference/commerce/post-api-v1-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.
