Update Quote Overview
39 min
update quote overview the update quote api changes an existing quote and re runs the same pricing and tax cascade the nue line editor runs internally it is the write counterpart to create quote docid\ bc idxynwaus7o9efycwq same pricing engine, same product shape, same preview semantics applied to a quote that already exists use it to change header attributes, edit or delete lines, add products and bundles, reconfigure a bundle's options, swap or remove price tags, and correct addresses with totals, metrics, and tax recalculated in the same call everything on this page has an exact order equivalent see update order overview docid\ gm0oxvhu351idx6gf9oqa endpoints endpoint method description /cpq/quotes/{quoteid}\ update post apply one or more update actions to an existing quote there is no separate preview endpoint preview is iscommit false on the same call action oriented, not payload oriented this is the most important thing to understand about the api, and the way it differs from every other write surface in nue you do not send the quote you want you send what you want done payload oriented (what this api is not ) action oriented (what this api is ) you send the full desired record and its lines an ordered list of actions, each naming an operation and its own payload server does diffs your document against stored state and infers intent executes exactly the operations you named omitting a field means ambiguous clear it, or leave it alone? unambiguous it is untouched omitting a line means ambiguous delete it, or leave it alone? untouched deletion only happens if you send deletelineitems concurrency last writer clobbers the whole record only the fields and lines you named are written concretely a put style api that received a quote with three lines when the stored quote has five would have to guess whether you meant to delete two this api never guesses you delete a line by asking for it, in a deletelineitems action, by id three consequences worth internalizing every action is a true patch updateheaderfields changes only the keys you include in fieldvalues updatelineitems changes only the keys you include on the lines you name everything else on the quote is left exactly as it was there is no "desired line set " a lineset style whole tree diff was designed and deliberately not built line changes are always delta actions updatelineitems , deletelineitems , addlineitems reconfiguring a bundle is not a verb there is no reconfigurebundle action you add, delete, or re quantify the bundle's option lines, and the server rewires the bundle tree see reconfiguring a bundle docid\ j9w7ufhjvphiej93bx5y9 contrast with patch /api/objects/{objectname}/{id} the generic objects api writes the field you send and recalculates nothing a start date or address changed that way leaves the quote with stale totals and stale tax the update quote api exists precisely to close that gap it applies the change and re runs pricing, roll ups, and tax use the objects api for administrative bookkeeping; use this api for anything that touches money, dates, quantity, or the line set request envelope { "iscommit" true, "recalc" "auto", "expectedlastmodified" "2026 08 07t18 22 41 000z", "actions" \[ { "action" "\<actionname>", "payload" { / action specific / } } ] } field type required default description iscommit boolean no true true persists the result false runs the full cascade in memory and persists nothing must be a real boolean a string is rejected with 400 iscommit must be a boolean recalc string no auto auto , pricing only , tax only , or none case sensitive see recalculation modes docid\ j9w7ufhjvphiej93bx5y9 expectedlastmodified string no optimistic concurrency guard when set, the update fails with quote modified unless it matches the quote's current last modified timestamp actions array yes ordered list of actions must be non empty the quote is identified by the {quoteid} path parameter do not put quoteid in the body the rest body has no such field (the apex global method does; see global methods docid\ j9w7ufhjvphiej93bx5y9 ) the six actions action payload what it does updateheaderfields { "fieldvalues" { } } patches header fields standard and custom updatelineitems { "lineitems" \[ { "lineitemid" " ", "fieldvalues" { } } ] } patches fields on existing lines, addressed by line id deletelineitems { "lineitemids" \[ " ", " " ] } removes lines by id, cascading to their children and private tags addlineitems { "products" \[ productinput ] } adds products and bundles using the same recursive shape as create quote set parentlineid to add an option under an existing bundle replacepricetags { "pricetags" \[ { "\<oldidorcode>" "\<newidorcode>" } ], "target" \[ ], "includechildren" true } swaps a tag for another on every scoped line that carries the old tag removepricetags { "pricetags" \[ "\<idorcode>" ], "target" \[ ], "includechildren" true } removes tags from the scoped lines and reprices without them a seventh action, repricequote , is internal sending it is rejected an unrecognized action name returns 400 unknown action \<name> action ordering is not your problem you may send actions in any order the server normalizes them into a canonical sequence before executing header fields → deletes → price tag actions → line updates → adds this ordering exists so that header context (price book, currency, dates, discount) is established before adds resolve their price book entry, and so deletes settle before edits and adds are targeted the re ordering is a stable sort by stage actions move into their stage, and within a stage they keep the order you sent them in for most requests that makes the result fully order independent, because the conflict rules force each line to be targeted at most once, so the actions inside a stage cannot overlap the exception is the price tag stage removepricetags and replacepricetags occupy the same stage, and the conflicting actions check does not inspect their target line ids — only updatelineitems and deletelineitems targets are checked so two price tag actions may legitimately touch the same lines, and when they do they execute in the order you sent them and the outcome depends on that order if a removepricetags and a replacepricetags in one request overlap on the same lines or the same tag, order them deliberately, or split them into two requests two conflicts are rejected before anything is written conflict result updateheaderfields appears more than once in one request conflicting actions combine them into a single action the same line is targeted by more than one action in one request conflicting actions each line may be touched at most once a header pricing change and a line pricing change may coexist the header discount is distributed across the lines that this request did not explicitly price field naming use nue field names over rest rest fieldvalues keys are validated against the nue object describe for quote (header actions) and quotelineitem (line actions) use the nue camelcase api names quantity , discount , subscriptionterm , netsalesprice , paymentterm , includedunits , evergreen an unknown key fails fast at the proxy, before anything reaches salesforce 400 invalid field for quote paymentterm c 400 invalid field for quote line item quantity c custom fields are addressed by their salesforce api name, exactly as on the create quote path region c , costcenter c salesforce field api names ( subscriptionterm c , discount c ) are for the apex global methods, not for rest the rest proxy rejects them if you are porting apex sample code to rest, translate every fieldvalues key to its nue name first recalculation modes recalc selects which callouts run auto is the default and the right answer almost always mode what runs use it when auto re prices and/or re taxes based on which fields you actually changed default you do not want to decide what to recompute pricing only re prices and rolls up header totals; skips tax tax is disabled or owned downstream; batch edits that defer tax to a final call; a fast price only preview tax only re runs tax and tax roll ups; leaves pricing untouched an address, tax code, or exemption change without disturbing negotiated prices none persists the change and recomputes nothing administrative, non pricing fields only can leave stale totals an invalid value returns recalc invalid the check is case sensitive auto is not auto under auto , whether pricing runs is decided by which fields you touched header fields that drive a re price discount , discountamount , totalprice , partnerpayoutpercentage , partnerpayoutamount , subscriptionstartdate , subscriptionenddate , subscriptionterm , subscriptiontermdimension header fields that drive tax only shippingstreet , shippingcity , shippingstate , shippingpostalcode , shippingcountry , isshippingaddresssameasbilling , the five taxation address fields, taxationaccount , entityusecode , taxcompanycode line fields that drive a re price quantity , netsalesprice , discount , discountamount , subscriptionstartdate , subscriptionenddate , subscriptionterm , includedunits , evergreen plus any custom field mapped as a line direct quantity tier attribute, since editing one can move the resolved tier everything else is persisted without a re price if you change a field that is not on these lists and you want it to affect price, that is what pricing only is for pricing engine plugins and recalc your active pricing engine plugins run as part of the update, exactly as they do on create the reprice loads them and hands them to the engine on every pricing call, so a plugin that overrides a metric, adjusts a price, or emits a tag behaves the same whether the record was built by create quote or edited by update quote which plugins run every active plugin scoped headerobject , lineitem , or any , on the beforecalculation , aftercalculation , or afterrampgeneration trigger events any scoped plugins are included the update path deliberately uses the scope inclusive lookup recalc decides whether your plugins run at all plugins execute only when the request actually triggers a pricing call they do not run when recalc is none or tax only , and they do not run under auto if you only touched fields that don't re price (billing period, payment term, notes, a plain custom field) if you depend on a plugin to populate a custom metric or price, make sure the edit reaches the pricing pass send pricing only if auto would skip it preview runs them too iscommit false skips only the persist phase, so plugins execute on a preview exactly as on a commit worth knowing if a plugin of yours has side effects two behaviors specific to the update path, as opposed to create only price tags already persisted on the line reach the engine; the price book entry auto tag channel is suppressed on a reprice, so a tag removed earlier is never resurrected by a later update tags emitted by a plugin are persisted with the result, including plugin tags that carry no identity of their own preview vs commit iscommit false runs the identical code path load, apply actions, price, tax entirely in memory and stops before persistence iscommit false iscommit true (or omitted) database writes none one bulk persist pricing + tax callouts yes yes response shape identical identical side effects none no change history, no result persistence full salesforceurl in the response absent present preview and commit return the same computed amounts field for field use preview to answer "what would +10 quantity do to acv and tax?" without touching the record transaction semantics the whole update is one synchronous transaction, executed in three phases validate and apply, in memory every action is validated, then executed against an in memory object graph header start/end dates are re derived from line min/max, bundle trees are rewired, and the dirty field analysis behind recalc auto is computed no callouts, no writes price and tax pricing rolls line subtotals up to header acv/tcv/arr/mrr/cmrr, re applies tags, and propagates header to line values (auto renew, payment term, billing frequency) tax runs when taxation is enabled and the change touched an address, amount, quantity, or the line set persist one bulk write of the fully computed result preview stops before this phase because it is one transaction, a pricing failure rolls the entire update back nothing is written, not even the fields that would have succeeded examples all examples use the nue api key header and https //api nue io patch header fields only the keys you send change everything else on the quote is untouched curl x post 'https //api nue io/cpq/quotes/0q0cu000001abcxuav\ 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", "paymentterm" "net 45", "region c" "emea" } } } ] }' edit a line, and preview it first 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 "0qlcu00000abcdefgh", fieldvalues { quantity 30, discount 15 } } ] } } ] }; const res = await fetch( 'https //api nue io/cpq/quotes/0q0cu000001abcxuav\ update', { method 'post', headers myheaders, body json stringify(edit) } ); const result = await res json(); console log(`preview total ${result quote totalamount}`); console log(`preview acv ${result quote acv}`); // happy with it? send the identical body with iscommit true add products and remove one, in a single call the server orders the delete before the add, regardless of the order you send them in curl x post 'https //api nue io/cpq/quotes/0q0cu000001abcxuav\ 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" \["0qlcu00000zzzyyxwv"] } } ] }' reconfiguring a bundle there is no reconfigure action you add an option under the bundle ( parentlineid ), re quantify an existing option, or delete one \# add an optional add on to a configured bundle curl x post 'https //api nue io/cpq/quotes/0q0cu000001abcxuav\ update' \\ h 'nue api key your api key here' \\ h 'content type application/json' \\ d '{ "iscommit" true, "recalc" "auto", "actions" \[ { "action" "addlineitems", "payload" { "products" \[ { "parentlineid" "0qlcu00000bundleaa", "productsku" "addon support", "uom" "license/month", "quantity" 2 } ] } } ] }' \# change a bundle option's quantity { "action" "updatelineitems", "payload" { "lineitems" \[ { "lineitemid" "0qlcu00000optionaa", "fieldvalues" { "quantity" 5 } } ] } } \# drop an optional add on { "action" "deletelineitems", "payload" { "lineitemids" \["0qlcu00000optionaa"] } } the server compares the resulting selection against the bundle's current children, rewires parent/root/summary links, and re applies price tags, pricing attributes, and price dimensions to the rebuilt lines quantity linked options recompute against the bundle quantity remove and replace price tags { "iscommit" true, "actions" \[ { "action" "removepricetags", "payload" { "pricetags" \["volume tier 2026"], "target" \["0qlcu00000abcdefgh"], "includechildren" true } } ] } { "iscommit" true, "actions" \[ { "action" "replacepricetags", "payload" { "pricetags" \[ { "partner disc 10" "partner disc 15" } ] } } ] } tags are referenced by id or code target scopes the action to specific lines; omit it to apply to every line includechildren defaults to true and extends a targeted parent to its children removing a tag that no scoped line carries returns 200 with a no applicable lines for tag warning, not an error correct an address and re tax without re pricing { "iscommit" true, "recalc" "tax only", "actions" \[ { "action" "updateheaderfields", "payload" { "fieldvalues" { "shippingstreet" "500 boren ave n", "shippingcity" "seattle", "shippingstate" "wa", "shippingpostalcode" "98109", "shippingcountry" "us" } } } ] } tax only re runs tax and the tax roll up and leaves every negotiated price alone see addresses and taxation docid\ j9w7ufhjvphiej93bx5y9 response 200 ok returns the recalculated quote, its lines, and any warnings { "quote" { "id" "0q0cu000001abcxuav", "name" "acme q3 expansion", "totalamount" 48250 00, "acv" 41000 00, "tcv" 41000 00, "tax" 3862 50, "currencyisocode" "usd" }, "quotelineitems" \[ { "id" "0qlcu00000abcdefgh", "quantity" 30, "discount" 15, "netsalesprice" 1254 60, "totalprice" 37638 00 }, { "id" "0qlcu00000newlinea", "quantity" 5, "netsalesprice" 2270 00, "totalprice" 11350 00, "changetype" "newproduct" } ], "warnings" \[] } field type description quote object the quote header with recalculated pricing, metrics, and tax quotelineitems array every line on the quote after the update, with hierarchy warnings array non blocking advisories { level, code, message } errors do not come back in the 200 body a failed update returns 400 (validation or business rule failure) or 500 , with the standard error envelope { "status" 400, "error" "failed to update quote", "message" "line '0qlcu00000abcdefgh' is a summary line and cannot be edited directly ", "errordetails" \[ { "code" "line not editable", "message" " " } ] } what you can change header fields header fields are patchable except for engine owned outputs and identity never updatable calculated by the pricing engine sending any of these returns field not updatable totalamount , subtotal , listtotal , grandtotal , systemdiscount , systemdiscountamount , totalcommittedamount , sellertotalamount , tax , acv , tcv , todayarr , todaycmrr , and id guarded separately field rule currencyisocode cannot be changed over rest the proxy rejects it first with currencyisocode is not updatable customerid / account cannot be changed on an existing quote pricebookid cannot be changed once the quote has priced lines pricebook change not allowed deliberately updatable inputs , despite looking like outputs discount , discountamount , totalprice , partnerpayoutpercentage , and partnerpayoutamount header totalprice behaves as a target total the engine back derives the discount that hits it header discountamount is a conserved target, allocated across lines cascades that fire on a header change , exactly as in the line editor header start/end dates re derive from line min/max a header start date change pushes down to line dates; end dates are recomputed from term a header term change co terminates lines and re annualizes metrics, converting per line uom dimension paymentterm and billcycleday push down to lines autorenew propagates to recurring and usage lines only a header discount is distributed across lines that this request did not explicitly price bundled child lines are excluded when both discount and discountamount are sent, the percentage wins line fields not every row in the line editor is editable, and the api follows the same rules line type editable deletable rule regular line item yes yes fully editable, including lines inside a bundle ramp segment ( rampitem ) no no system generated from the ramp schedule sending a date returns ramp segment dates locked ; anything else returns line not editable removable only with its parent summary line ( summaryitem ) no yes cascades a roll up of the lines beneath it change the pieces, not the summary removing it removes the whole group split line ( splititem ) no no managed by the split quote flow subscription context line ( changeassetid set) no no belongs to the change order flow required / bundled child quantity follows the parent no locked to the bundle remove or reconfigure the parent instead remove required child change line (cancel / upgrade / downgrade / swap / qty / term / renew) no not on its own remove its summary line to remove the whole change remove change line restricted newproduct line on a change order yes yes a net new line; behaves normally line fields you may set category fields re prices quantity and price levers quantity , discount , discountamount , netsalesprice yes term and dates subscriptionterm , subscriptionstartdate , subscriptionenddate , evergreen , firstfullcreditperiodstartdate yes metering includedunits yes billing and renewal billingperiod , billingtiming , paymentterm , billcycleday , billcyclestartmonth , autorenew , defaultrenewalterm , renewalupliftpercent no structure and admin description , milestones , linebucketid , cancellationdate no custom fields any custom field by api name only if it feeds tiered pricing (a line direct quantity tier attribute) line fields you may not set calculated and overwritten on recalc sending one returns field not updatable listprice , listtotalprice , salesprice , unitprice , netsellerprice , subtotal , totalprice , totalamount , sellertotalamount , taxamount , systemdiscount , systemdiscountamount , deltaacv , deltaarr , deltacmrr , deltatcv , deltacommittedarr , deltacommittedcmrr , actualquantity , actualsubscriptionterm , proratedquantity , partnerpayoutpercentage , partnerpayoutamount relationship and identity fields are blocked too id , quoteid , orderid , pricebookentryid , product2id , parentid , productoption a legitimate edit changes pricing, quantity, or schedule; never a line's identity or its place in a bundle a line total override does not exist totalprice is non updatable on a line to reach a target line total, send discount or netsalesprice instead the header level totalprice target does work that override lives only at the header precedence when several price levers are sent on one line netsalesprice beats discount beats discountamount when netsalesprice wins, a netsalesprice applied warning is returned adding and removing lines addlineitems takes the same recursive productinput shape as create quote productsku or productname , uom , quantity , startdate , enddate , subscriptionterm , discount , pricetags , custompricingattributes , customfields , and nested addons see quote data reference docid 4y kdzrsb1dwjdfhvytgo for the full field list two fields matter specifically on the update path field meaning parentlineid adds this product as an option child under the existing bundle line with that id resolved against that bundle's live option config may target the root bundle or a nested sub bundle omit it for a top level add productoptionid targets a specific bundle option slot explicitly, for example a dynamic option when set, productsku / productname become optional rules adding a bundle automatically pulls in its required children and required add ons recursively, all the way down you specify only the top of the tree new lines are stamped changetype newproduct deleting a bundle root removes its entire descendant closure, together with each line's private price tags and tiers you do not list the children adds are rejected on a ramped record add not allowed on ramped record if no price book entry survives the currency, uom, and pricing attribute filter, the add is rejected with no eligible price book entry rather than silently doing nothing sortorder is re sequenced only on insert line level custom fields customfields on a productinput sets custom fields directly on the line being created, in the same call { "action" "addlineitems", "payload" { "products" \[ { "productsku" "nue on salesforce", "uom" "user/month", "quantity" 25, "customfields" { "costcenter c" "cc 1042", "contractref c" "msa 2026 0417" } } ] } } to set a custom field on a line that already exists, put it in the line's fieldvalues under updatelineitems see custom fields docid\ bikygxx0nxr6hdnxuvitf 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 path for an address only edit the header carries a taxation override with two independent parts override request fields turns on when taxable address taxationstreet , taxationcity , taxationstate , taxationpostalcode , taxationcountry taxationcountry is non null taxation customer identity taxationaccount it is non null either can be used alone or both together; clearing one does not affect the other each resolves through its own cascade, first match wins step taxable address taxation customer identity 1 quote taxation address if taxationcountry is set quote taxationaccount if set 2 account taxation address if taxationcountry is set account taxation customer if set 3 quote shipping address (default) account id and name (default) 4 account shipping address (fallback) each level is atomic the chosen level's fields are used as is and are never merged across levels the taxable address is honored by avatax, stripe tax, sphere, and anrok the taxation customer identity is honored by anrok only , where it matches the exemption certificate on the other integrations it is saved but ignored a no op, not an error resolved taxation values freeze when the invoice activates change orders and renewals carry their own copy; cancellations, credit memos, refunds, voids, and write offs reuse the originating order's frozen values editability gates before any action runs, the record itself must be editable gate error quote is activated, ordered, or locked for approval quote not editable order is not in draft status order not draft record id does not exist quote not found / order not found expectedlastmodified does not match quote modified / order modified nothing is persisted caller lacks edit permission insufficient access common error codes code meaning unknown action the action name is not one of the six action not allowed an internal only action was sent in a public request conflicting actions duplicate updateheaderfields , or one line targeted twice recalc invalid recalc is not auto , pricing only , tax only , or none invalid field the field does not exist on the target object field not updatable the field is system managed or engine calculated pricebook change not allowed pricebookid changed on a quote that already has priced lines line not editable summary, split, ramp, or subscription context line quantity not editable the line's quantity is controlled by its bundle parent ramp segment dates locked ramp segment dates are owned by the ramp schedule remove required child a required or bundled child cannot be removed alone remove ramp segment a ramp segment cannot be removed alone remove change line restricted remove the summary line to remove the whole change add not allowed on ramped record lines cannot be added to a ramped record no eligible price book entry no pbe survived the currency / uom / attribute filter invalid price tag the price tag was not found or is inactive invalid lineitem reference the targeted line does not belong to this record pricing engine error pricing failed; nothing was committed common warnings netsalesprice applied , header discount applied , product discount overrides header , no applicable lines for tag , tax calculation failed , quantity not editable scope and limits this api is for quotes and for orders that have not been activated yet changes to live, activated subscriptions renewals, quantity changes, cancellations, and bundle reconfigurations on an activated order go through the change order docid\ ussheavdtd5efewfauylq process instead limit detail record size a record with 200 or more line items currently fails outright this is a hard ceiling today and applies to every action callouts pricing and tax are synchronous http callouts budget at least one of each per recalc a header carrying partnerpayoutamount without a percentage triggers a two pass pricing call tax failures surface as warnings, not hard errors, and leave amounts without tax bundle reconfigure on a change quote not yet emitted as change lines under a reconfigure parent pre order, net new bundles work today editing the change carried by a change line not supported apex global methods in org and managed package callers can use the apex global methods directly, with no http globalapitypes updatequoteresponse globalquoteserviceapi updatequote(globalapitypes updatequoterequest req) globalapitypes updateorderresponse globalorderserviceapi updateorder(globalapitypes updateorderrequest req) two differences from rest the record id is a field on the request ( req quoteid / req orderid ), not a path parameter fieldvalues keys are salesforce field api names ( subscriptionterm c , discount c ), case insensitive, with the namespace optional not the nue camelcase names rest uses the response is { status, data, warnings, errors } , where status is success or failure and errors are returned in the payload rather than as an http status there is also a salesforce apexrest surface for in org http callers post /services/apexrest/ruby/updatequote and /services/apexrest/ruby/updateorder , taking the same json body as the global method full apex documentation, including request construction and worked examples, lives in the nue knowledge center under global methods related pages create quote overview docid\ bc idxynwaus7o9efycwq the create counterpart update order overview docid\ gm0oxvhu351idx6gf9oqa the exact order equivalent preview vs commit docid 0jq3sd3mi6ejhjc69ovikcustom fields docid\ bikygxx0nxr6hdnxuvitfprice tags docid\ z5zott7eszhmhaxifqmkrquote data reference docid 4y kdzrsb1dwjdfhvytgochange quotes and orders docid\ ussheavdtd5efewfauylq for activated subscriptions