Update Order Overview
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, and the exact mirror of Update Quote.
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 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. This API applies the change and re-runs pricing, roll-ups, and tax in the same transaction.
See Action-oriented, not payload-oriented on the Quote page for the full explanation.
Request envelope
{
"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.
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 |
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 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.
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.
Examples
Patch order header fields
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
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
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.
{
"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
{
"action": "addLineItems",
"payload": {
"products": [
{
"productSku": "NUE_ON_SALESFORCE",
"uom": "User/Month",
"quantity": 25,
"customFields": { "CostCenter__c": "CC-1042" }
}
]
}
}See Custom Fields.
Response
{
"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[] }.
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.
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.
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
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 -- the create counterpart
- Update Quote Overview -- the full contract
- Change Quotes and Orders -- for activated subscriptions