Clone and Template Quotes
15 min
clone and template quotes rebuilding a complicated quote line by line is slow and risks silently dropping a negotiated price tag three endpoints let you start from a quote that already exists instead clone any quote, create a new quote from a curated template, or copy a template onto a quote you have already created all three carry over line items, applied line price tags and price tiers, and all three are available over rest, through the nue lifecycle manager mcp docid\ cf8cbhygypd3ozg7ym2gy , and as apex global methods inside the managed package which one to use you have you want use any quote — a revision, last year's renewal a new independent copy on the same account clone quote a curated template quote and an opportunity a new quote created and populated in one call create quote from template a curated template quote and a quote that already exists the template's lines copied into that quote copy quote from template endpoints endpoint method description /cpq/quotes/{quoteid}\ clone post copy any quote into a new draft quote /cpq/quotes\ createfromtemplate post create a quote on an opportunity from a template quote /cpq/quotes/{targetquoteid}\ copyfromtemplate post copy a template quote onto an existing quote all three are available on salesforce integrated tenants only a template carries the shape of a deal, never a locked price this is the single most important behaviour on this page, and the one most likely to surprise you a clone stays on its source's account its pricing, negotiated discounts and tax are copied across unchanged , because nothing about the customer changed a template is different createfromtemplate and copyfromtemplate always reprice the result against the target quote's own account a discount whose tier depends on the customer — headcount, volume, segment — re resolves to the target's band, not the template's tax is likewise recalculated for the target's own shipping jurisdiction, so a template built for a customer in one city and applied to a customer in another is taxed for the second customer expect the money to differ from the template whenever the two accounts resolve differently that is the design tax recalculation is best effort and is not reported back a tenant with taxation switched off, or a tax engine that rejects the target's address, still returns 200 if the tax figure matters, read the quote back and check it clone quote post /cpq/quotes/{quoteid}\ clone no request body { "quote" { "id" "0q0dh000002cp1xcaa", "name" "acme renewal copy" }, "lineitemscopied" 7, "pricetagscopied" 3 } key behaviors the source does not have to be a template quote use this to duplicate any quote the clone is always draft and is never marked primary it is named \<source name/> copy and stays on the source's opportunity the endpoint accepts no overrides — to change the name, opportunity, start date or subscription term, follow with update quote docid\ j9w7ufhjvphiej93bx5y9 price tags are always copied there is no flag to suppress them cloning a quote with zero line items succeeds and returns an empty draft quote that is not an error not idempotent each call creates another quote, and a request that times out may still have created one — look for a new draft quote on the source's opportunity before retrying create quote from template post /cpq/quotes\ createfromtemplate { "templatequoteid" "0q0dh000002cpbdcai", "opportunityid" "006dh00000abcdeaa3" } { "quote" { "id" "0q0dh000002cq44caa", "name" "standard platform deal" }, "lineitemscopied" 4, "pricetagscopied" 2 } key behaviors the source must be flagged as a template quote ( ruby is template quote c = true ) a non template source is refused with 400 and nothing is created the new quote is draft , never primary, and inherits the template's price book, subscription term and start date there is no pricebookid parameter the copy rejects any quote whose price book differs from the template's, so the new quote always takes the template's the endpoint accepts no name, date or term overrides — follow with update quote docid\ j9w7ufhjvphiej93bx5y9 header custom fields are not inherited a template supplies line items, not header values, so set header custom fields yourself on the follow up update line level custom fields do copy not idempotent each call creates another quote copy quote from template post /cpq/quotes/{targetquoteid}\ copyfromtemplate { "templatequoteid" "0q0dh000002cpbdcai" } { "targetquoteid" "0q0dh000002cq44caa", "skipped" false, "lineitemscopied" 4, "pricetagscopied" 2 } key behaviors the target must already exist this endpoint never creates a quote the template and target price books must match , and the template must have a price book header custom fields are not copied from the template; line level custom fields are always read skipped a repeat call is not always a repeat copy, and the response is 200 either way when the target already records this same template as the one it was built from, the call is a deliberate no op skipped true , lineitemscopied 0 , and nothing is repriced or re taxed that recording is what decides it — not the line items themselves — and only quotes created by createfromtemplate carry it a quote you assembled any other way records no template, so a second copy onto it is refused with 409 do not treat this endpoint as idempotent for a target you built yourself read the target first error responses status when 400 invalid request; the source is not a template quote; the template has no price book; the template and target price books differ 404 the source, template or target quote was not found 409 (copyfromtemplate only) the target already has lines and does not record this template not retryable without clearing the target first 500 internal server error the outcome is unknown — look for a newly created draft quote before retrying, or you may create a second one through the nue lifecycle manager mcp tool endpoint it calls clonequote /cpq/quotes/{quoteid}\ clone , then \ update for any override createquotefromtemplate /cpq/quotes\ createfromtemplate , then \ update for any override copyquotefromtemplate /cpq/quotes/{targetquoteid}\ copyfromtemplate the tools add conveniences the rest contract does not have clonequote and createquotefromtemplate accept name , startdate and subscriptionterm — and createquotefromtemplate also accepts customfields — and apply them as a follow up repricing update if the quote is created but that update fails, the tool returns partial success and names the quote that was created, so it can be corrected rather than orphaned silently apex global methods available inside the managed package for flows and apex callers quote clone = new ruby globalquoteservice() clonequote('0q04w000002rzitca0'); quote fromtemplate = new ruby globalquoteservice() createquotefromtemplate('0q04w000002rzitca1', '006dh00000abcdeaa3'); new ruby globalquoteservice() copyquotefromtemplate('0q04w000002rzitca1', '0q04w000002rzitca0'); one deliberate difference between apex and rest copyquotefromtemplate is a released global method, so it still accepts an ordinary quote as its source the rest and mcp surfaces refuse a non template source, so that they agree with createfromtemplate existing apex and flow callers are unaffected related create quote overview docid\ bc idxynwaus7o9efycwqupdate quote overview docid\ j9w7ufhjvphiej93bx5y9price tags docid\ z5zott7eszhmhaxifqmkrfinalize quotes to orders docid 7obzqa pnrgwffkjrk9gs