---
title: Change Quotes and Orders
slug: change-quotes-and-orders
docTags: 
createdAt: 2026-07-23T20:42:29.113Z
---

This guide introduces Lifecycle Manager **Change Quotes and Orders** and provides request examples for every change type. The **same endpoint** — `POST /cpq/change-order` — produces either a **change quote** or a **change order** depending on `options.proceedOption`, so it covers both. See the [Create Change Order API reference](<API References/openapi-spec-lifecycle.json>) for the full schema.

## Lifecycle Manager — Change Orders

In Lifecycle Manager, a **change order** modifies a customer's existing **subscriptions, assets, and entitlements** *after* the initial sale — renewals, quantity and term changes, price adjustments, reconfigurations, cancellations, free-trial conversions, field updates, and **cross-sell** (adding brand-new products). A single change order can contain multiple changes and can also add new products in the same request.

Every change order is a `POST /cpq/change-order` with a top-level `assetChanges` array (the modifications to existing subscriptions) and, optionally, a top-level `products` array (brand-new products to add — see [Cross-sell](docId\:USsHEavDTd5EFewFaUYlQ) below).

### Change quote vs. change order (`proceedOption`)

Two `options` fields control the outcome — the container (`proceedOption`) and whether it activates (`activateOrder`):

- `proceedOption` chooses the container the change lands in:
  - `CreateOrder` — create a change order.
  - `CreateQuote` — create a change quote for review/approval (optionally pass an `opportunityId` to tie it to an existing opportunity).
  - `UseExistingOrder` / `UseExistingQuote` — append the change into an existing draft order or quote, identified by `containedObjectId`.
- `activateOrder` controls activation. Note that `proceedOption: "CreateOrder"` does **not** by itself activate — pair it with `activateOrder` to choose draft vs. activated.

| `proceedOption`    | `activateOrder`  | Result                                                                          |
| ------------------ | ---------------- | ------------------------------------------------------------------------------- |
| `CreateOrder`      | `false`          | **Draft** change order                                                          |
| `CreateOrder`      | `true`           | **Activated** change order                                                      |
| `CreateQuote`      | see note         | Change quote for review/approval (optionally on an `opportunityId`)             |
| `UseExistingOrder` | `false` / `true` | Append into an existing draft order (`containedObjectId`); activate when `true` |
| `UseExistingQuote` | see note         | Append into an existing quote (`containedObjectId`)                             |

**Quote modes +&#x20;**`activateOrder`**:** the published API contract states that with `activateOrder: true` a quote mode is "converted to an order and activated" — but the current runtime does **not** cleanly do that: quote modes return a **quote ID**, skip invoice generation, and the Apex activation helper only activates orders. Treat `activateOrder` on `CreateQuote` / `UseExistingQuote` as **version-dependent** and verify it in your target environment rather than relying on auto-activation.

```javascript
// Draft change order — CreateOrder WITHOUT activation
{
  "options": {
    "proceedOption": "CreateOrder",
    "activateOrder": false
  },
  "assetChanges": [...]
}

// Change quote tied to an opportunity
{
  "options": {
    "proceedOption": "CreateQuote",
    "activateOrder": false,
    "opportunityId": "006Ru00000K5bY9IAJ"  // Optional: associate with opportunity
  },
  "assetChanges": [...]
}
```

**Note:** the published Create Change Order API reference is intentionally minimal/generic — this guide is the practical examples page. See the [Create Change Order API reference](<API References/openapi-spec-lifecycle.json>) for schema field details only.

### Cross-sell: adding new products

Beyond modifying existing subscriptions through `assetChanges`, a change order can **add brand-new products** in the same request using the top-level `products` array. For each entry in `products`, the behavior is **exactly the same as adding new products in a new quote** — same shape as [Create Quote](<Guides and Examples/Customer Lifecycle/CPQ Revenue Lifecycle/Quotes/Create Quote Overview.mdx>) products, resolved and priced through the same pricing pipeline. The `products` array is additive to `assetChanges`, which remains required and non-empty.

The one difference is at the header: the new products' metrics — **ARR, CMRR, TCV, and ACV** — roll up into the change order header **together with** the metrics of the change itself. In other words, the header totals reflect both the `assetChanges` and the newly added `products` combined. Full details and examples are in [New Product (Cross-Sell / Cancel + Replace)](docId\:USsHEavDTd5EFewFaUYlQ).

### Change types

| Change type                    | `changeType`                        | What it does                                                                                          |
| ------------------------------ | ----------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Update Quantity                | `UpdateQuantity`                    | Increase or reduce quantity (delta) on a subscription, usage, credit, asset, or entitlement.          |
| Update Term                    | `UpdateTerm`                        | Add or subtract months from a subscription's term (`term` is a delta).                                |
| Renew                          | `Renew`                             | Renew for another term, or convert to evergreen.                                                      |
| Adjust Price                   | `AdjustPrice`                       | Apply a discount % or override the net sales price.                                                   |
| Reconfigure                    | `Reconfigure`                       | Change a bundle's add-ons/configuration; also covers Upgrade/Downgrade/Swap.                          |
| Cancel                         | `Cancel`                            | Cancel a subscription immediately or at end of term.                                                  |
| New Product (Cross-Sell)       | `NewProduct` / top-level `products` | Add a brand-new product or bundle; supports cancel-and-replace.                                       |
| Convert Free Trial             | `ConvertFreeTrial`                  | Convert a free trial to a paid or evergreen subscription.                                             |
| Update Fields on Subscriptions | `UpdateField`                       | Update editable fields on an existing subscription.                                                   |
| Co-Term                        | `CoTerm`                            | Align subscription end dates (see [Update Term](docId\:USsHEavDTd5EFewFaUYlQ)).                       |
| Upgrade / Downgrade / Swap     | `Upgrade` / `Downgrade` / `Swap`    | Move a subscription to a different product/edition (see [Reconfigure](docId\:USsHEavDTd5EFewFaUYlQ)). |

Every `assetChanges` entry carries `changeType` and, for all types that modify an existing subscription, an `assetNumber`. `NewProduct` is the only type that does not require an `assetNumber`.

## Update Quantity

`UpdateQuantity` isn't limited to subscription seats/licenses — the target `assetNumber` accepts a **subscription number or an asset/entitlement ID**, and it applies to any quantity-bearing line, including **usage, credits, assets, and entitlements**.

The `quantity` field in `UpdateQuantity` operations is a **delta** (change amount), not the final absolute quantity.

| Current Quantity | Delta Value | Result      |
| ---------------- | ----------- | ----------- |
| 10 seats         | `+25`       | 35 seats    |
| 100 licenses     | `-30`       | 70 licenses |
| 50 users         | `+50`       | 100 users   |

### Seat Expansion

Add 25 more user licenses to an existing subscription (e.g., from 10 → 35 seats):

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "UpdateQuantity",
      "assetNumber": "SUB-086067",
      "quantity": 25,  // Delta: adds 25 to current quantity (10 + 25 = 35)
      "startDate": "2024-01-01"
    }
  ]
}
```

### Seat Reduction

Reduce quantity by 5 (e.g., from 35 → 30 seats):

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "UpdateQuantity",
      "assetNumber": "SUB-086067",
      "quantity": -5,  // Delta: reduces current quantity (35 - 5 = 30)
      "startDate": "2024-01-01"
    }
  ]
}
```

## Update Term

`term` is a **delta**: the number of months to **add** (positive) or **subtract** (negative) from the current subscription term — not the final term. `UpdateTerm` changes the contract length; it does **not** convert billing frequency (e.g. monthly → annual).

### Extend Subscription Term

Add 6 months to the current subscription:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "UpdateTerm",
      "assetNumber": "SUB-086067",
      "term": 6
    }
  ]
}
```

### Extend the Term by a Year

Add 12 months to the current term. Because `term` is a delta, this **extends** the contract by a year — it does not change the billing frequency:

```javascript
POST /cpq/change-order
{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "UpdateTerm",
      "assetNumber": "SUB-086067",
      "term": 12
    }
  ]
}
```

### Co-Terminate Subscriptions

Use `changeType: "CoTerm"` with a `coTermDate` to align one or more subscriptions to the same end date:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "CoTerm",
      "assetNumber": "SUB-086067",
      "coTermDate": "2024-12-31"
    },
    {
      "changeType": "CoTerm",
      "assetNumber": "SUB-086068",
      "coTermDate": "2024-12-31"
    }
  ]
}
```

## Renew

### Standard Renewal

Renew a subscription for another 12 months:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Renew",
      "assetNumber": "SUB-086067",
      "renewalTerm": 12
    }
  ]
}
```

### Convert to Evergreen

Change from a fixed-term to an evergreen subscription:

```javascript
POST /cpq/change-order
{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Renew",
      "assetNumber": "SUB-086067",
      "switchToEvergreen": true
    }
  ]
}
```

## Adjust Price

### Percentage Discount

Apply a 20% discount to a subscription (optionally cascading to bundle children):

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "AdjustPrice",
      "assetNumber": "SUB-086067",
      "startDate": "2024-01-01",
      "discount": {
        "discountPercentage": 20,
        "applyToChildren": true
      }
    }
  ]
}
```

`discount.applyToChildren` is not limited to the targeted line — when set on a bundle parent, the percentage discount **cascades to the bundle's child subscriptions** as well. Leave it off (or `false`) to discount only the line named by `assetNumber`.

### Fixed Price Override

Set a specific net sales price for a subscription over a date range:

```javascript
POST /cpq/change-order
{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "AdjustPrice",
      "assetNumber": "SUB-086067",
      "netSalesPrice": 1200.00,
      "startDate": "2024-01-01",
      "endDate": "2024-12-31"
    }
  ]
}
```

### True-up to Quantity Tier

When a subscription is priced by a **quantity tier attribute** (for example, total committed amount or number of hosts), set `trueUpPrice: true` to recompute the line to the correct tier for the attribute's current value, without sending a discount or a fixed price:

```javascript
POST /cpq/change-order
{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "AdjustPrice",
      "assetNumber": "SUB-086067",
      "trueUpPrice": true,
      "startDate": "2024-01-01"
    }
  ]
}
```

:::hint{type="warning"}
**Over REST, a true-up does not cascade to bundle children.** The single-call `applyToChildren` cascade for `trueUpPrice` is available on the Apex Global Method only; the cpq REST API does not forward it yet. To true up a bundle over REST, send a separate `trueUpPrice` AdjustPrice for the parent **and one for each child subscription**. (The nested `discount.applyToChildren` shown under Percentage Discount is unaffected and still cascades a percentage change.)
:::

## Reconfigure

Reconfigure is a **parent operation**: its nested `addOnChanges` may contain the supported add-on operations, but the **same bundle, its parent, or its child subscriptions must not also be targeted by separate top-level asset changes** in the same request. Do not combine a top-level `Reconfigure` with other top-level change types against the same subscription tree.

Reconfigure does **not** auto-derive the diff for you — you submit the concrete add-on deltas yourself in `addOnChanges`, and Apex prices and persists what it receives. The supported add-on change types are exactly `UpdateQuantity`**,&#x20;**`Cancel`**, and&#x20;**`NewProduct`.

### Adding Add-Ons to a Bundle

Add additional features to an existing bundle:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": false,
    "proceedOption": "CreateQuote",
    "opportunityId": "006Ru00000K5bY9IAJ"
  },
  "assetChanges": [
    {
      "changeType": "Reconfigure",
      "assetNumber": "SUB-086067",
      "startDate": "2024-01-15",
      "addOnChanges": [
        {
          "changeType": "NewProduct",
          "productOptionId": "a8fRu0000002bOmIAI",
          "priceBookEntryId": "01uRu000004SyY7IAK",
          "productOptionQuantity": 3,
          "term": 12
        }
      ]
    }
  ]
}
```

### Complex Bundle Changes

Multiple add-on changes to a bundle in one operation:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Reconfigure",
      "assetNumber": "SUB-086067",
      "startDate": "2024-01-15",
      "addOnChanges": [
        {
          "changeType": "NewProduct",
          "productOptionId": "a8fRu0000002bOmIAI",
          "priceBookEntryId": "01uRu000004SyY7IAK",
          "productOptionQuantity": 2
        },
        {
          "changeType": "UpdateQuantity",
          "assetNumber": "SUB-086068",
          "productOptionQuantityChange": 5
        },
        {
          "changeType": "Cancel",
          "assetNumber": "SUB-086069",
          "cancellationDate": "2024-12-31"
        }
      ]
    }
  ]
}
```

### Upgrade, Downgrade & Swap

Move a subscription to a different product/edition with `changeType: "Upgrade"`, `"Downgrade"`, or `"Swap"`, targeting the new product via `targetPriceBookEntryId`. All three share the **same** request shape — the `changeType` value is the only difference; the direction (is the target really higher/lower?) is validated by the engine.

For a **standalone product**, `targetPriceBookEntryId` + `startDate` is all you need:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Upgrade",
      "assetNumber": "SUB-086067",
      "targetPriceBookEntryId": "01uRu000004SyY8IAK",
      "startDate": "2024-01-15"
    }
  ]
}
```

:::hint{type="warning"}
`quantity`**&#x20;is not allowed on Upgrade/Downgrade/Swap.** UDS quantities are fully derived — continuing lines keep their source subscription's quantity, and new lines book at the target bundle's configured defaults. Sending `quantity` is rejected with `PRODUCT_QUANTITY_NOT_ALLOWED`. To grow or shrink at the same time, add a separate `UpdateQuantity` change on the same asset in the same request.
:::

### Bundles: Upgrade/Downgrade/Swap with UDS

When the source or target is a **bundle**, the change is resolved by **Unified Data Structure (UDS)** logic: the engine maps each source subscription (the bundle root and its child options) onto the target bundle's option slots. Two extra fields on the asset change control this:

| Field             | Type  | Purpose                                                                                                                                                                                                                                                                                                                                                         |
| ----------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `addOns`          | Array | **Declares the target bundle's configuration** — which option slots are filled and with what. Each entry identifies its product one way (`priceBookEntryId` **or** `productSku`/`productName`) and names the slot with `productOptionId`. Recursive for nested bundles. Omit it to let the server build the target from the bundle's **default configuration**. |
| `transformations` | Array | **Pins** that tell the engine how a specific source subscription maps onto the target when it is not obvious — see [ambiguity](docId\:USsHEavDTd5EFewFaUYlQ) and [convergence](docId\:USsHEavDTd5EFewFaUYlQ) below.                                                                                                                                             |

If the target bundle has a **required feature** whose options aren't satisfiable by defaults, a bare U/D/S (no `addOns`) is rejected with `FEATURE_OPTION_COUNT_OUT_OF_RANGE` — supply `addOns` to choose the option(s):

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": false,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Upgrade",
      "assetNumber": "SUB-000014",              // source bundle subscription (e.g. Nue Star Edition)
      "targetPriceBookEntryId": "01uRu0000ESSNTL",  // target bundle (e.g. Nue Essential Package)
      "startDate": "2026-10-01",
      "addOns": [
        {
          "productOptionId": "a0qRu000PRICEBLDR",  // target slot: "Price Builder"
          "priceBookEntryId": "01uRu000PRICEBLDR"
        }
      ]
    }
  ]
}
```

When a bundle transforms, any **source child option that has no matching slot in the target bundle is cancelled** — the commit response reports it in `messages` as `SOURCE_CANCELLED` (e.g. `Source SUB-000015 has no candidate on the target and is cancelled`). This is expected; plan for child lines to drop when the target bundle is narrower than the source.

### Preview → resolve → commit

For any non-trivial bundle change, preview first. `POST /cpq/change-order:preview` takes the **same request body** but persists nothing and returns per-source pricing — or, when a source can't be mapped unambiguously, an `ambiguities[]` block instead of pricing:

```javascript
POST /cpq/change-order:preview   // same body as the commit request
```

- **Preview tolerates ambiguity** — it returns HTTP `200` with `ambiguities[]` (and a null `priceSummary` for that source).
- **Commit does not** — if you `POST /cpq/change-order` with an unresolved source, it is refused with HTTP `409` `RESOLUTION_REQUIRED` and the same `ambiguities` payload.

The loop is: **preview → read the candidates → pin each unresolved source with a&#x20;**`transformations`**&#x20;entry → commit.**

### Resolving ambiguity (one source, many targets)

An **ambiguity** (a "tie") is when a single source subscription could map to **more than one** slot in the target bundle. The engine won't guess. A preview surfaces the choices:

```javascript
// Response from POST /cpq/change-order:preview
{
  "results": [
    {
      "sourceAssetNumber": "SUB-000019",   // the source the rep must resolve
      "assetNumber": "SUB-000018",
      "priceSummary": null,                 // no price until the tie is resolved
      "ambiguities": [
        {
          "sourceAssetNumber": "SUB-000019",
          "sourceProductName": "QuickBooks Integration",
          "candidates": [
            {
              "targetProductOptionId": "a0qRu000INTEGPREM",
              "targetPriceBookEntryId": "01uRu000INTEGPREM",
              "targetProductName": "Premium Integrations",
              "changeType": "Upgrade",
              "targetKind": "BUNDLE",
              "listPrice": 30.0,
              "recommended": true
            },
            {
              "targetProductOptionId": "a0qRu000INTEGSTD",
              "targetPriceBookEntryId": "01uRu000INTEGSTD",
              "targetProductName": "Standard Integrations",
              "changeType": "Swap",
              "targetKind": "BUNDLE",
              "listPrice": 9.9,
              "recommended": false
            }
          ]
        }
      ]
    }
  ]
}
```

Pick a candidate and echo it back as a `transformations` pin keyed by the same `sourceAssetNumber`, then commit. A pin identifies its target **exactly one way** — either **explicit** (`targetProductOptionId` + `targetPriceBookEntryId` together) or **by-values** (`uom` / `customPricingAttributes` / `billingTiming`); sending both is rejected with `TRANSFORMATION_IDENTITY_CONFLICT`.

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Upgrade",
      "assetNumber": "SUB-000018",
      "targetPriceBookEntryId": "01uRu000TARGETBNDL",
      "startDate": "2026-10-01",
      "transformations": [
        {
          "sourceAssetNumber": "SUB-000019",        // resolve the ambiguous source…
          "targetProductOptionId": "a0qRu000INTEGPREM",  // …onto the chosen slot
          "targetPriceBookEntryId": "01uRu000INTEGPREM"
        }
      ]
    }
  ]
}
```

### Convergence (many sources, one target)

**Convergence** is the opposite of a tie: **several source subscriptions legitimately map onto the same target slot** and merge into one line. For example, a customer holds two separate integration add-ons — **QuickBooks Integration** and **Nue on Salesforce** — and the target bundle consolidates both under a single **Nue Platform** option. Both sources converge onto that one slot.

Unlike an ambiguity, convergence isn't a tie to break — each source maps to that shared slot deterministically. You express it by sending **one pin per source, all naming the same target** (converging pins from different sources are explicitly valid):

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Upgrade",
      "assetNumber": "SUB-000018",              // the source bundle root
      "targetPriceBookEntryId": "01uRu000TARGETBNDL",
      "startDate": "2026-10-01",
      "transformations": [
        {
          "sourceAssetNumber": "SUB-000019",        // QuickBooks Integration
          "targetProductOptionId": "a0qRu000NUEPLATFORM",
          "targetPriceBookEntryId": "01uRu000NUEPLATFORM"
        },
        {
          "sourceAssetNumber": "SUB-000020",        // Nue on Salesforce
          "targetProductOptionId": "a0qRu000NUEPLATFORM",  // same target slot → they converge
          "targetPriceBookEntryId": "01uRu000NUEPLATFORM"
        }
      ]
    }
  ]
}
```

On commit, the two source subscriptions are credited/updated and the target **Nue Platform** line carries the merged result — the engine converges them onto the single slot rather than creating two lines. As always, any source option that lands on **no** target slot is cancelled and reported via `SOURCE_CANCELLED`.

## Cancel

### Immediate Cancellation

Cancel a subscription immediately:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-086067",
      "cancellationDate": "2024-01-01"
    }
  ]
}
```

### End-of-Term Cancellation

Cancel at the end of the current term:

```javascript
POST /cpq/change-order
{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-086067",
      "cancellationDate": "2024-12-31"
    }
  ]
}
```

## New Product (Cross-Sell / Cancel + Replace)

There are two ways to add brand-new products as part of a change order:

1. The **top-level&#x20;**`products`**&#x20;array** — the same shape and behavior as adding products on a new quote, with metrics rolling up into the change order header. Best for straightforward cross-sell and cancel-and-replace.
2. The `NewProduct`**&#x20;change type** inside `assetChanges` — for adding a product/bundle alongside other asset changes, including full bundle hierarchies with configured and dynamic add-ons.

### When to use `products[]` vs `NewProduct`

| Use…                                         | When                                                                                                                                                                                                  |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Top-level&#x20;**`products[]`              | Straightforward cross-sell or cancel-and-replace; you want the new-quote product shape (resolve by `productSku`/`productName`, discounts, price tags) with header metric rollup. Recommended default. |
| `NewProduct`**&#x20;in&#x20;**`assetChanges` | You need to add into a bundle's add-on slots (`productOptionId`), reference an explicit `priceBookEntryId`, or use NewProduct-specific fields alongside other asset changes.                          |

A `NewProduct` asset change **must be accompanied by at least one other change** (it cannot be the only change), and `NewProduct` is the **only** change type that does not require an `assetNumber`. Most builds also expect a **non-empty&#x20;**`assetChanges` even when using top-level `products[]` (a products-only request may be rejected), but this is **deployment-dependent** — confirm it in your target environment.

### Adding products via the `products` array (cross-sell)

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "UpdateQuantity",
      "assetNumber": "SUB-086067",
      "quantity": 25,
      "startDate": "2024-01-01"
    }
  ],
  "products": [
    {
      "productSku": "SKU-ADDON-01",
      "quantity": 5,
      "subscriptionTerm": 12,
      "subscriptionTermDimension": "Months"
    }
  ]
}
```

Each entry uses the new-product request shape and supports the fields accepted by the **deployed API version** — `productSku`/`productName` (or `productOptionId` to target a specific bundle option slot), `quantity`, `startDate`/`endDate`, `subscriptionTerm`, `paymentTerm`, `coTermAsset` (to co-terminate the new line with an existing subscription), and nested `addOns`. **Verify discount, price-tag, and dynamic add-on behavior in your target environment** — these have had API-layer limitations on the change-order `products[]` path (see the discounts note below).

### Expansion (Renew + New Product)

Renew an existing subscription **and** add a brand-new product in the same change order. The `assetChanges` entry renews the existing line; the `products` entry adds the new line. Both roll up into the same change order header, so ARR, CMRR, TCV, and ACV reflect the renewal and the new product combined.

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Renew",
      "assetNumber": "SUB-086067",
      "renewalTerm": 12
    }
  ],
  "products": [
    {
      "productSku": "SKU-ADDON-01",
      "quantity": 10,
      "subscriptionTerm": 12,
      "subscriptionTermDimension": "Months"
    }
  ]
}
```

### Cancel and Replace (Swap Editions)

Cancel an existing product or bundle and replace it with a different one in a single change order — for example, replace **Nue Gem Edition** with **Nue Rise Edition**. The `Cancel` change removes the old subscription; the `products` entry adds the replacement. Header metrics (ARR, CMRR, TCV, ACV) net the cancellation against the replacement.

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-086067",
      "cancellationDate": "2026-08-01"
    }
  ],
  "products": [
    {
      "productName": "Nue Rise Edition",
      "quantity": 100,
      "subscriptionTerm": 36,
      "subscriptionTermDimension": "Months"
    }
  ]
}
```

When the item being replaced is a bundle, cancelling the original bundle cancels its child lines too, and the replacement bundle's children are added automatically — exactly as in a new quote.

### Applying Discounts and Price Tags to New Products

Products added through `products` accept the **same discounting inputs as a new quote**. Provide exactly one of `discount` (percentage), `discountAmount` (fixed amount), or `netSalesPrice` (explicit unit price) per line, and/or attach `priceTags` (price and discount tags referenced by `code` or `id`).

Percentage discount:

```javascript
"products": [
  {
    "productName": "Nue Rise Edition",
    "quantity": 100,
    "subscriptionTerm": 36,
    "subscriptionTermDimension": "Months",
    "discount": 15
  }
]
```

Fixed discount amount:

```javascript
"products": [
  {
    "productSku": "SKU-ADDON-01",
    "quantity": 10,
    "discountAmount": 500
  }
]
```

Price / discount tags (same as a new quote):

```javascript
"products": [
  {
    "productName": "Nue Rise Edition",
    "quantity": 100,
    "priceTags": [
      { "code": "PROMO-2026" }
    ]
  }
]
```

On the change-order `products[]` path, `discount`, `discountAmount`, `netSalesPrice`, and `priceTags` follow the new-quote product shape, but **line-level discounts and price tags are conditionally supported** and have had API-layer limitations (and preview defects) depending on the deployed version — verify them in your target environment before relying on them. When they do apply, the resulting line metrics roll up into the change order header alongside the change itself.

### The `NewProduct` change type (bundles & add-ons)

Use the `NewProduct` change type inside `assetChanges` to add a standalone product or a full bundle hierarchy alongside other asset changes. The new product's term can be set explicitly (`term`) or co-termed with an existing subscription (`coTermAsset`).

:::hint{type="warning"}
**Important**: `NewProduct` changes must be accompanied by at least one other change in the same request (e.g., Cancel, UpdateQuantity, Renew). `NewProduct` cannot be the only change in a change order.
:::

### NewProduct Fields

| Field                 | Type    | Required                | Description                                                                                                                         |
| --------------------- | ------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `changeType`          | String  | Yes                     | Must be `"NewProduct"`                                                                                                              |
| `priceBookEntryId`    | String  | Yes                     | Price book entry ID identifying the product to add                                                                                  |
| `startDate`           | Date    | Yes                     | Effective start date for the new product                                                                                            |
| `quantity`            | Decimal | Yes                     | Quantity to add (must be positive)                                                                                                  |
| `term`                | Decimal | One of term/coTermAsset | Subscription term in months. Mutually exclusive with `coTermAsset`                                                                  |
| `coTermAsset`         | String  | One of term/coTermAsset | Existing subscription number (e.g. `SUB-000192`) to co-term with. The new product's end date aligns to this subscription's end date |
| `netSalesPrice`       | Decimal | No                      | Override the calculated net sales price                                                                                             |
| `addOns`              | Array   | No                      | Bundle add-ons to include with the product (see add-on structure below)                                                             |
| `autoRenew`           | Boolean | No                      | Whether the subscription should auto-renew                                                                                          |
| `defaultRenewalTerm`  | Decimal | No                      | Renewal term in months when auto-renew is enabled                                                                                   |
| `billingTiming`       | String  | No                      | Billing timing, e.g. `In Advance`, `In Arrears`                                                                                     |
| `billingPeriod`       | String  | No                      | Billing frequency, e.g. `Month`, `Year`                                                                                             |
| `billCycleDay`        | String  | No                      | Day of the billing cycle                                                                                                            |
| `billCycleStartMonth` | String  | No                      | Starting month for annual billing cycles                                                                                            |
| `priceTagIds`         | Array   | No                      | Price tag IDs to apply discounts                                                                                                    |
| `priceTagCodes`       | Array   | No                      | Price tag codes (alternative to IDs)                                                                                                |
| `description`         | String  | No                      | Custom description                                                                                                                  |
| `customFields`        | Object  | No                      | Custom field values to populate on the order product                                                                                |

### Add-On Structure

Each add-on can contain nested `addOns`, supporting recursive bundle hierarchies.

| Field                   | Type    | Required         | Description                              |
| ----------------------- | ------- | ---------------- | ---------------------------------------- |
| `changeType`            | String  | Yes              | Must be `"NewProduct"`                   |
| `productOptionId`       | String  | Yes (configured) | Product option ID for configured add-ons |
| `priceBookEntryId`      | String  | Yes (dynamic)    | Price book entry ID for dynamic add-ons  |
| `productOptionQuantity` | Decimal | Yes              | Quantity of the add-on                   |
| `subscriptionTerm`      | Decimal | No               | Term in months if different from parent  |
| `coTermAsset`           | String  | No               | Co-term with an existing subscription    |
| `subscriptionStartDate` | Date    | No               | Start date if different from parent      |
| `netSalesPrice`         | Decimal | No               | Override net sales price for this add-on |
| `billingTiming`         | String  | No               | Billing timing override                  |
| `billingPeriod`         | String  | No               | Billing period override                  |
| `billCycleDay`          | String  | No               | Bill cycle day override                  |
| `billCycleStartMonth`   | String  | No               | Bill cycle start month override          |
| `priceTagIds`           | Array   | No               | Price tag IDs                            |
| `priceTagCodes`         | Array   | No               | Price tag codes                          |
| `addOns`                | Array   | No               | Nested add-ons (recursive)               |
| `customFields`          | Object  | No               | Custom field values                      |

### Basic New Product

Cancel an existing subscription and add a new product with a 12-month term:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-000192",
      "cancellationDate": "2025-02-15"
    },
    {
      "changeType": "NewProduct",
      "priceBookEntryId": "01uRu000004SyY8IAK",
      "startDate": "2025-02-15",
      "quantity": 3,
      "term": 12
    }
  ]
}
```

### New Product with Bundle Add-Ons

Add a new bundle product with configured and dynamic add-ons:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-000192",
      "cancellationDate": "2025-02-15"
    },
    {
      "changeType": "NewProduct",
      "priceBookEntryId": "01uRu000004SyY8IAK",
      "startDate": "2025-02-15",
      "quantity": 3,
      "term": 12,
      "addOns": [
        {
          "changeType": "NewProduct",
          "productOptionId": "a0jRu0000002bOmIAI",
          "productOptionQuantity": 3
        },
        {
          "changeType": "NewProduct",
          "productOptionId": "a0jRu0000002bOnIAI",
          "priceBookEntryId": "01uRu000004SyY7IAK",
          "productOptionQuantity": 10
        }
      ]
    }
  ]
}
```

### New Product Co-Termed with Existing Subscription

Align the new product's end date to an existing subscription instead of specifying a term:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-000192",
      "cancellationDate": "2025-02-15"
    },
    {
      "changeType": "NewProduct",
      "priceBookEntryId": "01uRu000004SyY8IAK",
      "startDate": "2025-02-15",
      "quantity": 5,
      "coTermAsset": "SUB-000200"
    }
  ]
}
```

### New Product with Price Override

Override the calculated price at both the parent and add-on level:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": false,
    "proceedOption": "CreateQuote"
  },
  "assetChanges": [
    {
      "changeType": "Cancel",
      "assetNumber": "SUB-000192",
      "cancellationDate": "2025-02-15"
    },
    {
      "changeType": "NewProduct",
      "priceBookEntryId": "01uRu000004SyY8IAK",
      "startDate": "2025-02-15",
      "quantity": 3,
      "term": 12,
      "netSalesPrice": 450.00,
      "addOns": [
        {
          "changeType": "NewProduct",
          "productOptionId": "a0jRu0000002bOmIAI",
          "productOptionQuantity": 10,
          "netSalesPrice": 25.00
        }
      ]
    }
  ]
}
```

## Convert Free Trial

### Convert Trial to Paid

Convert a free trial to a paid subscription:

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "ConvertFreeTrial",
      "assetNumber": "SUB-086067",
      "startDate": "2024-01-15",
      "term": 12,
      "overrideTrialEnd": true
    }
  ]
}
```

### Convert Trial to Evergreen

Convert a trial directly to an evergreen subscription:

```javascript
POST /cpq/change-order
{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "ConvertFreeTrial",
      "assetNumber": "SUB-086067",
      "startDate": "2024-01-15",
      "switchToEvergreen": true,
      "coTermToBundleSubscription": false
    }
  ]
}
```

## Update Fields on Subscriptions

Update editable fields on an existing subscription **without changing its commercial terms** — for example, updating the `Description` or a custom field. Use `changeType: "UpdateField"` with the target `assetNumber` and a `fieldsToUpdate` list of `{ fieldApiName, newValue }` pairs. Values are always provided as **strings** and are coerced to the field's type on the Salesforce side. An optional `startDate` sets the effective date, and `applyToChildren` cascades the update to a bundle's child subscriptions. `UpdateField` is currently documented and tested as a **standalone** change type — send it on its own, **not mixed with other change types** (e.g. `AdjustPrice`, `UpdateQuantity`) in the same request.

:::hint{type="warning"}
`UpdateField`**&#x20;is deployment-dependent.** It requires the corresponding backend and Salesforce metadata in the target environment (e.g. the change-type picklist value and any referenced fields); older REST deployments may not support it or may reject the request at validation before it reaches Apex. As of July 2026 some environments still have a registration gap — the change-type picklist value or the REST route for `UpdateField` may be missing even where the underlying Apex is present — so confirm support in your target environment before relying on it. Field API names must be **org-qualified** on a namespaced org (e.g. `Ruby__BillingPeriod__c`) — an unqualified name is ignored.
:::

### UpdateField Fields

| Field                           | Type    | Required | Description                                                 |
| ------------------------------- | ------- | -------- | ----------------------------------------------------------- |
| `changeType`                    | String  | Yes      | Must be `"UpdateField"`                                     |
| `assetNumber`                   | String  | Yes      | Subscription (asset) number to update                       |
| `startDate`                     | Date    | No       | Effective date of the field update                          |
| `applyToChildren`               | Boolean | No       | Cascade the update to the subscription's bundle children    |
| `fieldsToUpdate`                | Array   | Yes      | List of fields to set on the subscription                   |
| `fieldsToUpdate[].fieldApiName` | String  | Yes      | API name of the field to update (e.g. `"Description"`)      |
| `fieldsToUpdate[].newValue`     | String  | Yes      | New value to set, as a string (coerced to the field's type) |

### Update One or More Fields

```javascript
POST /cpq/change-order

{
  "options": {
    "activateOrder": true,
    "proceedOption": "CreateOrder"
  },
  "assetChanges": [
    {
      "changeType": "UpdateField",
      "assetNumber": "SUB-086067",
      "startDate": "2026-08-01",
      "fieldsToUpdate": [
        { "fieldApiName": "Description", "newValue": "Renewed per Q3 amendment" },
        { "fieldApiName": "PO_Number__c", "newValue": "PO-2026-0042" }
      ]
    }
  ]
}
```
