---
title: Create Quote Overview
slug: create-quote-overview
docTags: 
createdAt: 2026-03-17T21:13:54.077Z
---

# Create Quote Overview

The Nue CPQ Quote API provides REST endpoints for programmatically creating fully-priced quotes with the same pricing fidelity as the Nue UI. Use the CPQ REST API when you need to build quotes outside of the Nue application -- for example, from a custom storefront, a partner portal, an AI agent, or any backend integration that requires real-time pricing.

If you are working with post-quote lifecycle operations such as order activation, subscription management, or asset tracking, use the [Lifecycle Manager API](../../Lifecycle%20Manager/Orders/Orders%20Overview.mdx) instead. The CPQ REST API is focused on quote creation and pricing.

## Endpoints

| Endpoint                | Method | Description                                       |
| ----------------------- | ------ | ------------------------------------------------- |
| `/cpq/quotes`           | POST   | Create and persist a quote (commit mode)          |
| `/cpq/quotes:preview`   | POST   | Preview a quote without persisting (dry-run mode) |
| `/cpq/quotes/{quoteId}` | GET    | Retrieve a quote's JSON representation            |

## How It Works

When you submit a Create Quote request, the pricing engine performs the following steps:

1. **Product Resolution** -- Finds products by SKU or name, resolves the correct Price Book Entry based on UOM, currency, and pricing attributes
2. **Bundle Expansion** -- Automatically includes bundled items, auto-populates required add-ons, resolves dynamic product options
3. **Pricing Engine Execution** -- Calculates the full pricing formula chain: `ListPrice x Quantity x Term = ListTotal`, then applies system discounts and discretionary discounts to arrive at the final total price
4. **Discount Propagation** -- Applies header-level discounts to all undiscounted lines, propagates parent-level discounts to children, respects explicit overrides
5. **Price Tag Evaluation** -- Evaluates tiered, volume, and ramp price/discount tags; applies auto-attached tags from product configuration
6. **Validation** -- Enforces business rules and returns structured error messages or warnings

## Key Concepts

### Preview vs Commit

The CPQ API supports two modes with identical request bodies:

| Mode              | Endpoint                   | Persists to Database | `quote.id` in Response |
| ----------------- | -------------------------- | -------------------- | ---------------------- |
| Preview (dry-run) | `POST /cpq/quotes:preview` | No                   | `null`                 |
| Commit            | `POST /cpq/quotes`         | Yes                  | Returns a UUID         |

Preview mode runs the full pricing engine but writes nothing to the database. Use it for pricing previews, what-if scenarios, and validation. Commit mode runs the same engine and persists the result. See [Preview vs Commit](docId:0JQ3SD3mI6ejHJc69oVik) for detailed examples.

### Product Identification

Products are identified by SKU and Unit of Measure (UOM). The SKU resolves the product, and the UOM resolves the specific Price Book Entry that determines the list price.

- **SKU + UOM** (recommended): `{ "productSku": "NUE_PLATFORM", "uom": "User/Month" }`
- **Name + UOM**: `{ "productName": "Nue Platform", "uom": "User/Month" }`
- **Price Book Entry ID**: `{ "priceBookEntryId": "PBE-001" }`

When both `productSku` and `productName` are provided, the SKU is used for product resolution.

### Pricing Formula

The pricing engine applies the following formula for recurring products:

```javascript
ListTotal = ListPrice x Quantity x Term
SubTotal  = ListTotal - SystemDiscount
Total     = SubTotal  - DiscretionaryDiscount
```

One-time products use `ListTotal = ListPrice x Quantity` (no term multiplier).

## Prerequisites

Before creating quotes, ensure you have:

- A valid Nue API key with quote creation permissions
- An Opportunity ID to associate with the quote
- Products published to your Price Book with Price Book Entries
- Knowledge of product SKUs and their Units of Measure (UOM)

## Authentication

All CPQ operations require authentication using your Nue API key in the `nue-api-key` header:

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

## Minimal Example -- Preview a Quote

```bash
curl -X POST 'https://api.nue.io/cpq/quotes:preview' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "Q1 2026 Platform License",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      { "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 }
    ]
  }'
```

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

const quoteData = {
  opportunityId: "006xx000001abc123",
  name: "Q1 2026 Platform License",
  subscriptionStartDate: "2026-01-01",
  subscriptionEndDate: "2027-01-01",
  subscriptionTermDimension: "Month",
  subscriptionTerm: 12,
  products: [
    { productSku: "NUE_PLATFORM", uom: "User/Month", quantity: 10 }
  ]
};

fetch('https://api.nue.io/cpq/quotes:preview', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  console.log('Quote preview:', result);
  console.log(`Total Amount: $${result.quote.totalAmount}`);
  console.log(`Line items: ${result.quoteLineItems.length}`);
  // the quote object has no id in preview mode
})
.catch(error => console.log('Error:', error));
```

## Minimal Example -- Commit a Quote

To persist the quote, use the `/cpq/quotes` endpoint (without `:preview`). The request body is identical.

```bash
curl -X POST 'https://api.nue.io/cpq/quotes' \
  -H 'nue-api-key: YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "opportunityId": "006xx000001abc123",
    "name": "Q1 2026 Platform License",
    "subscriptionStartDate": "2026-01-01",
    "subscriptionEndDate": "2027-01-01",
    "subscriptionTermDimension": "Month",
    "subscriptionTerm": 12,
    "products": [
      { "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 }
    ]
  }'
```

```javascript
fetch('https://api.nue.io/cpq/quotes', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
  console.log(`Quote ID: ${result.quote.id}`);  // present -- quote is persisted
  console.log(`Total Amount: $${result.quote.totalAmount}`);
})
.catch(error => console.log('Error:', error));
```

## Request Structure

The Create Quote request body has three main sections:

### Quote Header Fields

| Field                       | Type    | Required | Description                                                 |
| --------------------------- | ------- | -------- | ----------------------------------------------------------- |
| `opportunityId`             | string  | Yes      | The Opportunity ID to associate with the quote              |
| `name`                      | string  | Yes      | The quote name                                              |
| `subscriptionStartDate`     | date    | Yes      | Start date (YYYY-MM-DD)                                     |
| `subscriptionEndDate`       | date    | No       | End date; calculated from term if not provided              |
| `subscriptionTerm`          | number  | Yes      | Term length (e.g., 12 for 12 months)                        |
| `subscriptionTermDimension` | string  | No       | `"Month"` (default) or `"Year"`                             |
| `priceBookId`               | string  | No       | Price Book ID; uses system default if omitted               |
| `discount`                  | number  | No       | Header-level discount percentage (0-100)                    |
| `discountAmount`            | number  | No       | Header-level discount as fixed amount                       |
| `billingPeriod`             | string  | No       | `"Monthly"`, `"Quarterly"`, `"Semi-Annually"`, `"Annually"` |
| `billingTiming`             | string  | No       | `"In Advance"` or `"In Arrears"`                            |
| `autoRenew`                 | boolean | No       | Auto-renew setting for all products                         |
| `currencyIsoCode`           | string  | No       | ISO currency code for multi-currency orgs                   |
| `priceTags`                 | array   | No       | Quote-level price/discount tags                             |

### Product Input Fields

| Field                     | Type    | Required    | Description                                                                                                                                                                                          |
| ------------------------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productSku`              | string  | Yes\*       | Product SKU (either SKU or name required)                                                                                                                                                            |
| `productName`             | string  | Yes\*       | Product name (alternative to SKU)                                                                                                                                                                    |
| `uom`                     | string  | Conditional | Unit of Measure; required if `priceBookEntryId` is not provided                                                                                                                                      |
| `quantity`                | number  | No          | Product quantity (defaults vary by product)                                                                                                                                                          |
| `startDate`               | date    | No          | Product start date; defaults to quote start date                                                                                                                                                     |
| `endDate`                 | date    | No          | Product end date                                                                                                                                                                                     |
| `subscriptionTerm`        | number  | No          | Per-product term override                                                                                                                                                                            |
| `discount`                | number  | No          | Line-level discount percentage (0-100)                                                                                                                                                               |
| `discountAmount`          | number  | No          | Line-level discount amount                                                                                                                                                                           |
| `billingPeriod`           | string  | No          | Per-product billing period override                                                                                                                                                                  |
| `billingTiming`           | string  | No          | Per-product billing timing override                                                                                                                                                                  |
| `autoRenew`               | boolean | No          | Per-product auto-renew override                                                                                                                                                                      |
| `evergreen`               | boolean | No          | Whether the product is evergreen                                                                                                                                                                     |
| `renewalTerm`             | number  | No          | Renewal term override                                                                                                                                                                                |
| `priceTags`               | array   | No          | Line-level price/discount tags                                                                                                                                                                       |
| `addOns`                  | array   | No          | Add-on products for bundles (recursive ProductInput)                                                                                                                                                 |
| `customPricingAttributes` | array   | No          | Custom attributes for multi-attribute PBE resolution                                                                                                                                                 |
| `customFields`            | object  | No          | Custom field values applied to the line item, keyed by Salesforce API name (for example a Line Attribute's mapped field)                                                                             |
| `rampValues`              | array   | No          | Per-ramp Line Attribute values for a ramped line. Each entry targets one ramp line by `rampLineIndex` and sets custom fields on that ramp line. See the Per-ramp Line Attribute values section below |

### Price Tag Input

| Field  | Type   | Required       | Description        |
| ------ | ------ | -------------- | ------------------ |
| `code` | string | One of code/id | The price tag code |
| `id`   | string | One of code/id | The price tag ID   |

### Per-ramp Line Attribute values

On a ramped (multi-year) line, a custom field mapped as a Line Attribute can carry a different value for each ramp line. Pass these per-ramp values with the `rampValues` array on the product. Omit it and every ramp line inherits the value on the line, then the Pricebook Entry default.

| Field           | Type   | Required | Description                                                                                                                                                                                             |
| --------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rampLineIndex` | number | Yes      | The ramp line to target, 1-based in schedule order (the first ramp line is `1`)                                                                                                                         |
| `startDate`     | date   | No       | The ramp line's start date, accepted as a readable alias for `rampLineIndex`. Ramp line dates are derived by the pricing engine, so this is not the addressing key; when both are given they must agree |
| `fieldValues`   | object | Yes      | Field API name to value, applied to that ramp line only (for example `{ "Overage_Rate__c": 3.00 }`)                                                                                                     |

Each ramp line resolves its value from the first available of: an explicit `rampValues` entry, the value set on the line, the product's Pricebook Entry default, then empty. A `rampLineIndex` that is out of range, not a positive integer, or duplicated across entries is rejected with `INVALID_RAMP_LINE`.

### Example -- different overage rate each year

```json
{
  "opportunityId": "006xx000001abc123",
  "name": "3-Year Usage Ramp",
  "subscriptionStartDate": "2026-01-01",
  "subscriptionTermDimension": "Year",
  "subscriptionTerm": 3,
  "products": [
    {
      "productSku": "API_USAGE",
      "uom": "Call/Month",
      "quantity": 100,
      "priceTags": [ { "code": "3-YEAR-RAMP" } ],
      "rampValues": [
        { "rampLineIndex": 1, "fieldValues": { "Overage_Rate__c": 3.00 } },
        { "rampLineIndex": 2, "fieldValues": { "Overage_Rate__c": 3.50 } },
        { "rampLineIndex": 3, "fieldValues": { "Overage_Rate__c": 4.00 } }
      ]
    }
  ]
}
```

## Response Structure

The quote and its line items are returned at the top level of the response body:

```json
{
  "quote": { ... },
  "quoteLineItems": [ ... ]
}
```

- `quote` -- The quote header object with all calculated pricing fields
- `quoteLineItems` -- Array of root line items; bundle children are nested in `childrenLineItems` on their parent line, not flattened into this array

In preview mode the `quote` object has no `id`, and each line item carries a temporary id of the form `temp_<uuid>`. In commit mode `quote.id` holds the persisted quote ID and line items carry their real IDs.

On failure, the response is an HTTP error status with this body:

```json
{
  "status": 400,
  "error": "Failed to create quote",
  "message": "The field 'accountId' is required.",
  "errorDetails": [
    {
      "errorCode": "QUOTE_ACCOUNTID_REQUIRED",
      "message": "The field 'accountId' is required."
    }
  ]
}
```

Here `status` is the numeric HTTP status and the per-error list is `errorDetails`. Basic request validation failures, such as a missing `name` or `priceBookId`, return `"error": "Bad Request"` with no `errorDetails` array.

## Guide Articles

| Article                                                  | Description                                                |
| -------------------------------------------------------- | ---------------------------------------------------------- |
| [Preview vs Commit](docId:0JQ3SD3mI6ejHJc69oVik)         | Understand the difference between dry-run and commit modes |
| [Standalone Products](docId\:IuPfrldiwGoEheMeYAdPb)      | Create quotes with simple standalone products              |
| [Bundles](docId\:fri8QGGG2M1jVPi-Qlnvi)                  | Work with bundle products and add-ons                      |
| [Discounts](docId\:Y9AwhgT5IYIBlYMwVE6nX)                | Apply header, parent, and line-level discounts             |
| [Quantity Tier Attributes](docId\:pLcj0tpEnt2LihN0h6QGj) | Configure quantity-based pricing tiers                     |
