---
title: Update Order Overview
slug: update-order-overview
createdAt: 2026-08-07T12:00:00.000Z
---

# Update Order Overview

The Update Order API changes an existing **Draft** order and re-runs the same pricing and tax cascade the Nue Line Editor runs internally. It is the write counterpart to [Create Order](docId\:qDvlx6WS2ASCbu8HwFrZF), and the exact mirror of [Update Quote](docId\:J9W7UfHJvphiEJ93BX5y9).

Quote and Order share the same Line Editor, the same pricing engine, and the same tax cascade, so every operation, action name, payload shape, ordering rule, recalc mode, and error code is identical. Read [Update Quote Overview](docId\:J9W7UfHJvphiEJ93BX5y9) for the full contract. This page covers the endpoint and the handful of things that differ on orders.

## Endpoints

| Endpoint                       | Method | Description                                                 |
| ------------------------------ | ------ | ----------------------------------------------------------- |
| `/cpq/orders/{orderId}:update` | POST   | Apply one or more update actions to an existing Draft order |

There is no separate preview endpoint. Preview is `isCommit: false` on the same call.

## Action-oriented, not payload-oriented

You do not send the order you want. You send an ordered list of **actions** naming what to do, each with its own payload. Fields you omit are untouched; lines you omit are untouched. A line is deleted only when you ask for it by id in a `deleteLineItems` action -- the server never infers a deletion from a shorter line list.

This is what separates the Update Order API from `PATCH /api/objects/Order/{id}`. The Objects API writes the field you send and recalculates nothing, leaving totals and tax stale. Partner payout is an exception: `PATCH /api/objects/Order/{id}` with `partnerPayoutPercentage` or `partnerPayoutAmount` re-prices the order, with the same validation as Update Order, while partner fields are not supported on `PATCH /api/objects/OrderList` and `POST /api/objects/composite/*List`, which return `400` wherever your API role can reach them. This API applies the change *and* re-runs pricing, roll-ups, and tax in the same transaction.

See [Action-oriented, not payload-oriented](docId\:J9W7UfHJvphiEJ93BX5y9) on the Quote page for the full explanation.

## Request envelope

```json
{
  "isCommit": true,
  "recalc": "AUTO",
  "expectedLastModified": "2026-08-07T18:22:41.000Z",
  "actions": [
    { "action": "<actionName>", "payload": { /* action-specific */ } }
  ]
}
```

The order is identified by the `{orderId}` path parameter. Do not put `orderId` in the body.

## The six actions

Identical to the Quote API:

| Action               | Payload                                                                               |
| -------------------- | ------------------------------------------------------------------------------------- |
| `updateHeaderFields` | `{ "fieldValues": { ... } }`                                                          |
| `updateLineItems`    | `{ "lineItems": [ { "lineItemId": "...", "fieldValues": { ... } } ] }`                |
| `deleteLineItems`    | `{ "lineItemIds": [ "..." ] }`                                                        |
| `addLineItems`       | `{ "products": [ ProductInput ] }`                                                    |
| `replacePriceTags`   | `{ "priceTags": [ { "<old>": "<new>" } ], "target": [...], "includeChildren": true }` |
| `removePriceTags`    | `{ "priceTags": [ "<idOrCode>" ], "target": [...], "includeChildren": true }`         |

Actions are re-ordered server-side into the canonical sequence -- header fields, deletes, price-tag actions, line updates, adds. `updateHeaderFields` may appear at most once, and each line may be targeted at most once; both violations return `CONFLICTING_ACTIONS`.

The sort is stable **by stage**: within a stage, actions keep the order you sent them. That is immaterial everywhere except the price-tag stage, where `removePriceTags` and `replacePriceTags` share a stage and their `target` line ids are not covered by the conflict check -- so two overlapping tag actions run in submitted order and the result depends on it. See [Action ordering](docId\:J9W7UfHJvphiEJ93BX5y9).

## What differs from the Quote API

|                                 | Quote                                                                                | Order                                                |
| ------------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------- |
| Path                            | `/cpq/quotes/{quoteId}:update`                                                       | `/cpq/orders/{orderId}:update`                       |
| Editability gate                | Quote must not be activated, ordered, or locked for approval -- `QUOTE_NOT_EDITABLE` | Order must be in `Draft` status -- `ORDER_NOT_DRAFT` |
| Not-found error                 | `QUOTE_NOT_FOUND`                                                                    | `ORDER_NOT_FOUND`                                    |
| Concurrency error               | `QUOTE_MODIFIED`                                                                     | `ORDER_MODIFIED`                                     |
| Header object validated against | `Quote`                                                                              | `Order`                                              |
| Line object validated against   | `QuoteLineItem`                                                                      | `OrderProduct`                                       |
| Invalid-field message           | `Invalid field for quote: ...`                                                       | `Invalid field for order: ...`                       |
| Invalid line-field message      | `Invalid field for quote line item: ...`                                             | `Invalid field for order product: ...`               |
| Response keys                   | `quote`, `quoteLineItems`                                                            | `order`, `orderProducts`                             |
| Contract-value fields           | `ACV`, `TCV`                                                                         | `orderACV`, `orderTCV`                               |
| Apex global method              | `GlobalQuoteServiceAPI.updateQuote`                                                  | `GlobalOrderServiceAPI.updateOrder`                  |

:::hint{type="warning"}
**Draft only.** An activated order cannot be edited through this API. Changes to live, activated subscriptions -- renewals, quantity changes, cancellations, and bundle reconfigurations -- go through the [Change Order](docId\:USsHEavDTd5EFewFaUYlQ) process instead.
:::

## Field naming: use Nue field names over REST

`fieldValues` keys are validated against the Nue object describe for `Order` (header actions) and `OrderProduct` (line actions). Use the Nue camelCase API names -- `name`, `paymentTerm`, `billCycleDay`, `subscriptionTerm`, `quantity`, `discount`, `netSalesPrice`, `includedUnits`, `evergreen`. Custom fields use their Salesforce API name (`Region__c`).

An unknown key fails at the proxy with `400 Invalid field for order: <name>`. Salesforce field API names such as `SubscriptionTerm__c` are for the Apex global method, not for REST.

## Recalculation modes

`AUTO` (default), `PRICING_ONLY`, `TAX_ONLY`, `NONE` -- case-sensitive, same semantics as on quotes. See [Recalculation modes](docId\:J9W7UfHJvphiEJ93BX5y9).

Pricing engine plugins run on the update exactly as they do on create -- but only when the request actually reaches the pricing pass. They do not run under `recalc: NONE` or `TAX_ONLY`, nor under `AUTO` when you only touched non-repricing fields. Preview runs them too. See [Pricing engine plugins and  recalc](docId\:J9W7UfHJvphiEJ93BX5y9).

## Examples

### Patch order header fields

```bash
curl -X POST 'https://api.nue.io/cpq/orders/801cU000004AbcDEFG:update' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "isCommit": true,
    "recalc": "AUTO",
    "actions": [
      {
        "action": "updateHeaderFields",
        "payload": {
          "fieldValues": {
            "name": "Acme - Q3 Expansion Order",
            "poNumber": "PO-2026-0417",
            "paymentMethod": "Invoice"
          }
        }
      }
    ]
  }'
```

### Edit a line and preview the impact

```javascript
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");

const edit = {
  isCommit: false,                 // preview -- nothing is written
  recalc: "AUTO",
  actions: [
    {
      action: "updateLineItems",
      payload: {
        lineItems: [
          { lineItemId: "802cU00000AbcDeFGH", fieldValues: { quantity: 30, discount: 15 } }
        ]
      }
    }
  ]
};

const res = await fetch(
  'https://api.nue.io/cpq/orders/801cU000004AbcDEFG:update',
  { method: 'POST', headers: myHeaders, body: JSON.stringify(edit) }
);
const result = await res.json();

console.log(`Preview total:     ${result.order.totalAmount}`);
console.log(`Preview order ACV: ${result.order.orderACV}`);
```

### Add a product and delete another in one call

```bash
curl -X POST 'https://api.nue.io/cpq/orders/801cU000004AbcDEFG:update' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "isCommit": true,
    "recalc": "AUTO",
    "actions": [
      {
        "action": "addLineItems",
        "payload": {
          "products": [
            { "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 5 }
          ]
        }
      },
      {
        "action": "deleteLineItems",
        "payload": { "lineItemIds": ["802cU00000ZzzYyXWV"] }
      }
    ]
  }'
```

### Add a bundle option (reconfigure)

There is no reconfigure action -- you add, re-quantify, or delete the bundle's option lines. `parentLineId` points at the bundle line.

```json
{
  "isCommit": true,
  "recalc": "AUTO",
  "actions": [
    {
      "action": "addLineItems",
      "payload": {
        "products": [
          {
            "parentLineId": "802cU00000BundleAA",
            "productSku": "ADDON_SUPPORT",
            "uom": "License/Month",
            "quantity": 2
          }
        ]
      }
    }
  ]
}
```

### Line-level custom fields on an added line

```json
{
  "action": "addLineItems",
  "payload": {
    "products": [
      {
        "productSku": "NUE_ON_SALESFORCE",
        "uom": "User/Month",
        "quantity": 25,
        "customFields": { "CostCenter__c": "CC-1042" }
      }
    ]
  }
}
```

See [Custom Fields](docId\:BikyGXx0Nxr6hDnXuVITf).

## Response

```json
{
  "order": {
    "id": "801cU000004AbcDEFG",
    "name": "Acme - Q3 Expansion Order",
    "status": "Draft",
    "totalAmount": 48250.00,
    "orderACV": 41000.00,
    "orderTCV": 41000.00,
    "tax": 3862.50,
    "currencyIsoCode": "USD"
  },
  "orderProducts": [
    { "id": "802cU00000AbcDeFGH", "quantity": 30, "discount": 15, "netSalesPrice": 1254.60, "totalPrice": 37638.00 },
    { "id": "802cU00000NewLineA", "quantity": 5,  "netSalesPrice": 2270.00, "totalPrice": 11350.00, "changeType": "NewProduct" }
  ],
  "warnings": []
}
```

| Field           | Type   | Description                                                  |
| --------------- | ------ | ------------------------------------------------------------ |
| `order`         | object | The order header with recalculated pricing, metrics, and tax |
| `orderProducts` | array  | Every order product after the update, with hierarchy         |
| `warnings`      | array  | Non-blocking advisories -- `{ level, code, message }`        |

Failures return `400` or `500` with `{ status, error, message, errorDetails[] }`. Each `errorDetails` entry has an `errorCode` and a `message`. See [Response](docId\:J9W7UfHJvphiEJ93BX5y9) on the Quote page.

## What you can change

The rules are identical to quotes, with `OrderProduct` field names in place of `QuoteLineItem` names.

**Header fields never updatable** -- `FIELD_NOT_UPDATABLE`: `totalAmount`, `totalAmountWithoutTax`, `subtotal`, `listTotal`, `grandTotal`, `systemDiscount`, `systemDiscountAmount`, `totalCommittedAmount`, `sellerTotalAmount`, `tax`, `orderACV`, `orderTCV`, `todayARR`, `todayCMRR`, `id`.

**Deliberately updatable inputs:** `discount`, `discountAmount`, `totalPrice`, `partnerPayoutPercentage`, `partnerPayoutAmount`.

**Partner payout.** Send one of the two partner fields; Nue derives the other. Sending both returns `PARTNER_PAYOUT_MUTUALLY_EXCLUSIVE`. Use the Nue names -- the `Ruby__PartnerPayout*__c` names return `400 Invalid field`. Beyond the quote rules in [Partner payout](docId\:J9W7UfHJvphiEJ93BX5y9):

| Condition                                                                                                                                                                                                | Error                          |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| `partnerPayoutPercentage` outside 0-100, or a payout amount that is negative, greater than the total price, or greater than zero on an order whose total price is `0`                                    | `INVALID_PARTNER_PAYOUT_RANGE` |
| Partner field with `recalc: TAX_ONLY` or `NONE`                                                                                                                                                          | `RECALC_MODE_NOT_SUPPORTED`    |
| Partner field together with a change to `status` (for example activating the order) in the same request (re-sending the current status is fine). Update the partner payout first, then change the status | `CONFLICTING_ACTIONS`          |

Change orders follow the change-quote rules: the header percentage applies to every change line, an amount converts to a percentage against the change total (summary line excluded), and a negative line's payout is the percentage x its total. The summary line's percentage is its payout divided by its own total. Set the payout here after the change order is created: `POST /cpq/change-order` and `POST /cpq/change-order:preview` ignore partner payout fields (the request succeeds and nothing is written). Under `recalc: PRICING_ONLY`, a change order keeps its stored tax and `totalAmount` = `totalPrice` + that tax.

**Guarded separately:** `currencyIsoCode` cannot change; the account cannot change; `priceBookId` cannot change once the order has priced lines (`PRICEBOOK_CHANGE_NOT_ALLOWED`).

**Line fields that re-price:** `quantity`, `netSalesPrice`, `discount`, `discountAmount`, `subscriptionStartDate`, `subscriptionEndDate`, `subscriptionTerm`, `includedUnits`, `evergreen`, plus line-direct Quantity Tier Attribute custom fields.

**Line fields saved without re-pricing:** `billingPeriod`, `billingTiming`, `paymentTerm`, `billCycleDay`, `billCycleStartMonth`, `autoRenew`, `defaultRenewalTerm`, `description`, `cancellationDate`.

**Line fields never updatable:** `listPrice`, `listTotalPrice`, `unitPrice`, `netSellerPrice`, `subtotal`, `totalPrice`, `totalAmount`, `totalAmountWithoutTax`, `sellerTotalAmount`, `tax`, `systemDiscount`, `systemDiscountAmount`, every `delta*` metric, `actualQuantity`, `actualSubscriptionTerm`, `proratedQuantity`, `partnerPayoutPercentage`, `partnerPayoutAmount` -- plus identity and relationship fields `id`, `orderId`, `priceBookEntryId`, `productId`, `parentOrderProductId`, `productOptionId`.

**Line-type rules** are the same: summary, split, ramp, and subscription-context lines are not editable; required and bundled children cannot be removed alone; removing a bundle root removes its whole descendant closure; change lines are removed only via their summary line.

## Addresses and taxation

An address or taxation-override change always triggers a tax recalculation when taxation is enabled, then rolls the header total up. `recalc: TAX_ONLY` is the cheap address-only path. The taxable-address override (five `taxation*` fields, activated by `taxationCountry`) and the taxation-customer identity resolve independently, Order first, then Account. See [Addresses and taxation](docId\:J9W7UfHJvphiEJ93BX5y9).

## Scope and limits

- **Draft orders only.** Activated orders go through the Change Order API.
- Large records are supported; a single request is bounded by Apex governor limits rather than by a fixed line-item count.
- Pricing and tax are synchronous callouts; budget at least one of each per recalc.
- Tax failures surface as warnings, not errors.

## Apex global method

```apex
GlobalAPITypes.UpdateOrderResponse GlobalOrderServiceAPI.updateOrder(GlobalAPITypes.UpdateOrderRequest req)
```

The order id is `req.orderId`, and `fieldValues` keys are Salesforce field API names (`SubscriptionTerm__c`), not Nue names. The response is `{ status, data, warnings, errors }`. There is also an in-org apexrest surface at `POST /services/apexrest/Ruby/updateOrder` taking the same JSON body.

Full Apex documentation lives in the Nue Knowledge Center under **Global Methods**.

## Related pages

- [Create Order Overview](docId\:qDvlx6WS2ASCbu8HwFrZF) -- the create counterpart
- [Update Quote Overview](docId\:J9W7UfHJvphiEJ93BX5y9) -- the full contract
- [Custom Fields](docId\:BikyGXx0Nxr6hDnXuVITf)
- [Change Quotes and Orders](docId\:USsHEavDTd5EFewFaUYlQ) -- for activated subscriptions
