> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.solvimon.com/platform-guides/customers-and-billing/quoting/quote-templates/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.solvimon.com/_mcp/server. # Quote templates Quote templates pre-fill new quotes with reusable defaults: a pricing plan, subscription terms, quote content, and attached documents. Use them to cut manual entry and keep quotes consistent across your sales and billing teams. --- ## Why this matters If your team sends similar quotes repeatedly (same plan, same terms, same supporting documents), configuring each quote by hand is slow and error-prone. A template captures those defaults once. New quotes created from the template start pre-populated, and the sales rep only adjusts what's specific to the deal. ## What a template can define Every field on a template is optional; a template can define as much or as little as you like. A field you don't set is omitted from the template entirely (not stored as `null`), so it leaves the corresponding quote field untouched. | Area | Field | Description | | --------------------- | ----------------------------------------------- | ------------------------------------------------------------------ | | Pricing plan schedule | `pricing_plan_schedule.pricing_plan_version_id` | The pricing plan version the quote's schedule is created with. | | Subscription | `pricing_plan_subscription.billing_currency` | Default billing currency (alphabetic currency code). | | Subscription | `pricing_plan_subscription.initial_term` | Default initial subscription term, as a period (`type` + `value`). | | Subscription | `pricing_plan_subscription.renewal_term` | Default renewal term after the initial term. | | Subscription | `pricing_plan_subscription.auto_renewal` | Whether the resulting subscription renews automatically. | | Quote version | `quote_version.content` | Content of the initial quote version. | | Quote version | `quote_version.document_ids` | Documents attached to the initial quote version. | Templates follow the standard resource lifecycle: they are created in `DRAFT` status, must be activated before they can be used, and can be archived when no longer needed. ## Creating a template ### Via API Create a template with [POST /v1/quote-templates](https://docs.solvimon.com/api-docs/configuration-api/quote-templates/post-quote-templates). Only `name` and `reference` are required: ### Request POST [https://test.api.solvimon.com/v\{version}/quote-templates](https://test.api.solvimon.com/v\{version}/quote-templates) ```curl curl -X POST https://test.api.solvimon.com/v1/quote-templates \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "name": "Enterprise annual", "reference": "enterprise-annual", "description": "Default quote for enterprise deals: annual term, auto-renewal.", "pricing_plan_subscription": { "billing_currency": "EUR", "initial_term": { "type": "YEAR", "value": 1 }, "renewal_term": { "type": "YEAR", "value": 1 }, "auto_renewal": true }, "pricing_plan_schedule": { "pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z" }, "quote_version": { "document_ids": [ "doc_TcNqw8Hji4apQ3SS8Xp2" ] } }' ``` ```python import requests url = "https://test.api.solvimon.com/v1/quote-templates" payload = { "name": "Enterprise annual", "reference": "enterprise-annual", "description": "Default quote for enterprise deals: annual term, auto-renewal.", "pricing_plan_subscription": { "billing_currency": "EUR", "initial_term": { "type": "YEAR", "value": 1 }, "renewal_term": { "type": "YEAR", "value": 1 }, "auto_renewal": True }, "pricing_plan_schedule": { "pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z" }, "quote_version": { "document_ids": ["doc_TcNqw8Hji4apQ3SS8Xp2"] } } headers = { "X-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://test.api.solvimon.com/v1/quote-templates'; const options = { method: 'POST', headers: {'X-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"name":"Enterprise annual","reference":"enterprise-annual","description":"Default quote for enterprise deals: annual term, auto-renewal.","pricing_plan_subscription":{"billing_currency":"EUR","initial_term":{"type":"YEAR","value":1},"renewal_term":{"type":"YEAR","value":1},"auto_renewal":true},"pricing_plan_schedule":{"pricing_plan_version_id":"ppve_gwDeep0tDRcSvkAfeN1Z"},"quote_version":{"document_ids":["doc_TcNqw8Hji4apQ3SS8Xp2"]}}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://test.api.solvimon.com/v1/quote-templates" payload := strings.NewReader("{\n \"name\": \"Enterprise annual\",\n \"reference\": \"enterprise-annual\",\n \"description\": \"Default quote for enterprise deals: annual term, auto-renewal.\",\n \"pricing_plan_subscription\": {\n \"billing_currency\": \"EUR\",\n \"initial_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"renewal_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"auto_renewal\": true\n },\n \"pricing_plan_schedule\": {\n \"pricing_plan_version_id\": \"ppve_gwDeep0tDRcSvkAfeN1Z\"\n },\n \"quote_version\": {\n \"document_ids\": [\n \"doc_TcNqw8Hji4apQ3SS8Xp2\"\n ]\n }\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("X-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://test.api.solvimon.com/v1/quote-templates") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"name\": \"Enterprise annual\",\n \"reference\": \"enterprise-annual\",\n \"description\": \"Default quote for enterprise deals: annual term, auto-renewal.\",\n \"pricing_plan_subscription\": {\n \"billing_currency\": \"EUR\",\n \"initial_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"renewal_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"auto_renewal\": true\n },\n \"pricing_plan_schedule\": {\n \"pricing_plan_version_id\": \"ppve_gwDeep0tDRcSvkAfeN1Z\"\n },\n \"quote_version\": {\n \"document_ids\": [\n \"doc_TcNqw8Hji4apQ3SS8Xp2\"\n ]\n }\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://test.api.solvimon.com/v1/quote-templates") .header("X-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"name\": \"Enterprise annual\",\n \"reference\": \"enterprise-annual\",\n \"description\": \"Default quote for enterprise deals: annual term, auto-renewal.\",\n \"pricing_plan_subscription\": {\n \"billing_currency\": \"EUR\",\n \"initial_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"renewal_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"auto_renewal\": true\n },\n \"pricing_plan_schedule\": {\n \"pricing_plan_version_id\": \"ppve_gwDeep0tDRcSvkAfeN1Z\"\n },\n \"quote_version\": {\n \"document_ids\": [\n \"doc_TcNqw8Hji4apQ3SS8Xp2\"\n ]\n }\n}") .asString(); ``` ```php request('POST', 'https://test.api.solvimon.com/v1/quote-templates', [ 'body' => '{ "name": "Enterprise annual", "reference": "enterprise-annual", "description": "Default quote for enterprise deals: annual term, auto-renewal.", "pricing_plan_subscription": { "billing_currency": "EUR", "initial_term": { "type": "YEAR", "value": 1 }, "renewal_term": { "type": "YEAR", "value": 1 }, "auto_renewal": true }, "pricing_plan_schedule": { "pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z" }, "quote_version": { "document_ids": [ "doc_TcNqw8Hji4apQ3SS8Xp2" ] } }', 'headers' => [ 'Content-Type' => 'application/json', 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://test.api.solvimon.com/v1/quote-templates"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"name\": \"Enterprise annual\",\n \"reference\": \"enterprise-annual\",\n \"description\": \"Default quote for enterprise deals: annual term, auto-renewal.\",\n \"pricing_plan_subscription\": {\n \"billing_currency\": \"EUR\",\n \"initial_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"renewal_term\": {\n \"type\": \"YEAR\",\n \"value\": 1\n },\n \"auto_renewal\": true\n },\n \"pricing_plan_schedule\": {\n \"pricing_plan_version_id\": \"ppve_gwDeep0tDRcSvkAfeN1Z\"\n },\n \"quote_version\": {\n \"document_ids\": [\n \"doc_TcNqw8Hji4apQ3SS8Xp2\"\n ]\n }\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "X-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "name": "Enterprise annual", "reference": "enterprise-annual", "description": "Default quote for enterprise deals: annual term, auto-renewal.", "pricing_plan_subscription": [ "billing_currency": "EUR", "initial_term": [ "type": "YEAR", "value": 1 ], "renewal_term": [ "type": "YEAR", "value": 1 ], "auto_renewal": true ], "pricing_plan_schedule": ["pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z"], "quote_version": ["document_ids": ["doc_TcNqw8Hji4apQ3SS8Xp2"]] ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://test.api.solvimon.com/v1/quote-templates")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` ### Response (201) ```json { "object_type": "QUOTE_TEMPLATE", "id": "qute_UdPrx9Jkj5bqR4RR9Yq3", "name": "Enterprise annual", "reference": "enterprise-annual", "description": "Default quote for enterprise deals: annual term, auto-renewal.", "status": "DRAFT", "pricing_plan_subscription": { "billing_currency": "EUR", "initial_term": { "type": "YEAR", "value": 1 }, "renewal_term": { "type": "YEAR", "value": 1 }, "auto_renewal": true }, "pricing_plan_schedule": { "pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z" }, "quote_version": { "document_ids": [ "doc_TcNqw8Hji4apQ3SS8Xp2" ] }, "created_at": "2026-07-02T09:15:00Z", "updated_at": "2026-07-02T09:15:00Z" } ``` The template is created in `DRAFT` status. Activate it with [POST /v1/quote-templates/\{ref}/activate](https://docs.solvimon.com/api-docs/configuration-api/quote-templates/post-quote-templates-by-resource-id-or-reference-activate) before using it: ### Request POST [https://test.api.solvimon.com/v\{version}/quote-templates/\{resourceIdOrReference}/activate](https://test.api.solvimon.com/v\{version}/quote-templates/\{resourceIdOrReference}/activate) ```curl curl -X POST https://test.api.solvimon.com/v1/quote-templates//activate \ -H "X-API-KEY: " ``` ```python import requests url = "https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate" headers = {"X-API-KEY": ""} response = requests.post(url, headers=headers) print(response.json()) ``` ```javascript const url = 'https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate'; const options = {method: 'POST', headers: {'X-API-KEY': ''}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "net/http" "io" ) func main() { url := "https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate" req, _ := http.NewRequest("POST", url, nil) req.Header.Add("X-API-KEY", "") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate") .header("X-API-KEY", "") .asString(); ``` ```php request('POST', 'https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate', [ 'headers' => [ 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = ["X-API-KEY": ""] let request = NSMutableURLRequest(url: NSURL(string: "https://test.api.solvimon.com/v1/quote-templates/:resourceIdOrReference/activate")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` To change a template later, use [PATCH /v1/quote-templates/\{ref}](https://docs.solvimon.com/api-docs/configuration-api/quote-templates/patch-quote-templates-by-resource-id-or-reference). To retire one, use [POST /v1/quote-templates/\{ref}/archive](https://docs.solvimon.com/api-docs/configuration-api/quote-templates/post-quote-templates-by-resource-id-or-reference-archive). Both accept the resource ID or your own reference. ### Via Desk Open the quote template settings in the quote configuration section of Desk and fill in any of the fields above: optionally select a pricing plan version, set the subscription defaults, write the quote version content in the content editor, and attach documents. When you save, only the fields you set are stored; re-opening the template loads the saved values back into the form. ## Using a template when creating a quote Pass the template's ID as `template_id` when creating a quote with [POST /v1/quotes](https://docs.solvimon.com/api-docs/configuration-api/quotes/post-quotes). The quote starts pre-populated with the template's pricing plan, subscription terms, content and attachments, all of which can be adjusted before the quote is sent: ### Request POST [https://test.api.solvimon.com/v\{version}/quotes](https://test.api.solvimon.com/v\{version}/quotes) ```curl curl -X POST https://test.api.solvimon.com/v1/quotes \ -H "X-API-KEY: " \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cust_AbD3DqausjOYiMNDZY11F", "owner_user_id": "user_VeQsy1Klk6crS5QQ1Zr4", "template_id": "qute_UdPrx9Jkj5bqR4RR9Yq3" }' ``` ```python import requests url = "https://test.api.solvimon.com/v1/quotes" payload = { "customer_id": "cust_AbD3DqausjOYiMNDZY11F", "owner_user_id": "user_VeQsy1Klk6crS5QQ1Zr4", "template_id": "qute_UdPrx9Jkj5bqR4RR9Yq3" } headers = { "X-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://test.api.solvimon.com/v1/quotes'; const options = { method: 'POST', headers: {'X-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"customer_id":"cust_AbD3DqausjOYiMNDZY11F","owner_user_id":"user_VeQsy1Klk6crS5QQ1Zr4","template_id":"qute_UdPrx9Jkj5bqR4RR9Yq3"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://test.api.solvimon.com/v1/quotes" payload := strings.NewReader("{\n \"customer_id\": \"cust_AbD3DqausjOYiMNDZY11F\",\n \"owner_user_id\": \"user_VeQsy1Klk6crS5QQ1Zr4\",\n \"template_id\": \"qute_UdPrx9Jkj5bqR4RR9Yq3\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("X-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://test.api.solvimon.com/v1/quotes") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["X-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"customer_id\": \"cust_AbD3DqausjOYiMNDZY11F\",\n \"owner_user_id\": \"user_VeQsy1Klk6crS5QQ1Zr4\",\n \"template_id\": \"qute_UdPrx9Jkj5bqR4RR9Yq3\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://test.api.solvimon.com/v1/quotes") .header("X-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"customer_id\": \"cust_AbD3DqausjOYiMNDZY11F\",\n \"owner_user_id\": \"user_VeQsy1Klk6crS5QQ1Zr4\",\n \"template_id\": \"qute_UdPrx9Jkj5bqR4RR9Yq3\"\n}") .asString(); ``` ```php request('POST', 'https://test.api.solvimon.com/v1/quotes', [ 'body' => '{ "customer_id": "cust_AbD3DqausjOYiMNDZY11F", "owner_user_id": "user_VeQsy1Klk6crS5QQ1Zr4", "template_id": "qute_UdPrx9Jkj5bqR4RR9Yq3" }', 'headers' => [ 'Content-Type' => 'application/json', 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://test.api.solvimon.com/v1/quotes"); var request = new RestRequest(Method.POST); request.AddHeader("X-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"customer_id\": \"cust_AbD3DqausjOYiMNDZY11F\",\n \"owner_user_id\": \"user_VeQsy1Klk6crS5QQ1Zr4\",\n \"template_id\": \"qute_UdPrx9Jkj5bqR4RR9Yq3\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "X-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "customer_id": "cust_AbD3DqausjOYiMNDZY11F", "owner_user_id": "user_VeQsy1Klk6crS5QQ1Zr4", "template_id": "qute_UdPrx9Jkj5bqR4RR9Yq3" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://test.api.solvimon.com/v1/quotes")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` ### Response (201) ```json { "object_type": "QUOTE", "id": "quot_WfRtz2Lml7dsT6PP2As5", "created_at": "2026-07-02T09:20:00Z", "updated_at": "2026-07-02T09:20:00Z", "status": "DRAFT", "customer_id": "cust_AbD3DqausjOYiMNDZY11F", "owner_user_id": "user_VeQsy1Klk6crS5QQ1Zr4", "quote_version_infos": [ { "version": 1, "id": "quve_XgSua3Mnm8etU7NN3Bt6", "status": "DRAFT", "pricing_plan_subscription_id": "ppsu_YhTvb4Non9fuV8MM4Cu7" } ], "template_id": "qute_UdPrx9Jkj5bqR4RR9Yq3" } ``` In Desk, select the template in the quote creation form to pre-fill it the same way. > **Note** > > A template only sets the starting values of a quote. Editing a template later does not change quotes already created from it. ## Attachments Documents listed in `quote_version.document_ids` are carried onto the initial version of every quote created from the template. Use this for recurring supporting documents, such as standard terms or product sheets, so they don't have to be attached by hand each time. ## Edge cases * Only `ACTIVE` templates can be used to create quotes. A `DRAFT` template must be activated first; an `ARCHIVED` template can no longer be selected. * All defaulting fields are optional. A template that only sets, say, a billing currency leaves everything else for the rep to fill in. * If [default subscription settings](/platform-guides/customers-and-billing/quotes#pre-requisites) are also configured in the Settings menu, the template's values take precedence for quotes created from it. --- See also: [Quotes](/platform-guides/customers-and-billing/quotes), [Approval policy](/platform-guides/customers-and-billing/quotes/approval-policy) and [Subscriptions](/platform-guides/customers-and-billing/subscriptions).