Standalone Products
Standalone Products
Standalone products are individual, non-bundled products that can be added directly to a quote. Use this guide when you need to create quotes with simple products that do not have child components or add-on options. For bundle products with nested components, see the Bundles guide.
All examples below use the preview endpoint (POST /cpq/quotes:preview). To persist the quote, replace the URL with https://api.nue.io/cpq/quotes. The request body is identical for both modes.
Authentication
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");Example Products
The examples in this guide reference the following products from the Nue test catalog:
Product | SKU | UOM | List Price | Revenue Model |
|---|---|---|---|---|
Nue Platform | NUE_PLATFORM | User/Month | $15.00 | Recurring |
Nue on Salesforce | NUE_ON_SALESFORCE | User/Month | $29.90 | Recurring |
Implementation Service | IMPLEMENTATION_SERVICE | Hour | $250.00 | One-Time |
Unlimited Online Training | UNLIMITED_ONLINE_TRAINING | Account | $1,500.00 | One-Time |
USB Security Key | USB_SECURITY_KEY | Each | $45.00 | One-Time |
Key Behaviors
Behavior | Details |
|---|---|
UOM matching | The uom field must match a published Price Book Entry for the product. If no match is found, the API returns an error. |
Pricing formula (recurring) | ListPrice x Quantity x Term = ListTotal |
Pricing formula (one-time) | ListPrice x Quantity = ListTotal |
Date inheritance | If a product does not specify startDate or endDate, it inherits the quote-level subscriptionStartDate and subscriptionEndDate. |
Product resolution | Products are resolved by SKU (preferred) or name. The UOM determines which Price Book Entry is used. |
Discount propagation | A header-level discount applies to all lines that do not have their own explicit discount. |
Duplicate SKUs | The same SKU can appear multiple times in the products array. Each creates a separate line item. |
Use Case 1: Single Product
The simplest quote contains one recurring product identified by SKU and UOM. This example creates a quote for 10 users of Nue Platform at a 12-month term.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Single Product Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 }
]
}curl:
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": "Single Product Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 }
]
}'JavaScript fetch:
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Single Product Quote",
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(`Total Amount: $${result.quote.totalAmount}`);
console.log(`Line items: ${result.quoteLineItems.length}`); // 1
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Single Product Quote",
"totalAmount": 1800.00,
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01"
},
"quoteLineItems": [
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 10,
"listPrice": 15.00,
"listTotalPrice": 1800.00,
"totalPrice": 1800.00,
"startDate": "2026-01-01",
"endDate": "2027-01-01",
"childrenLineItems": []
}
]
}Pricing: $15.00 x 10 users x 12 months = $1,800.00.
Use Case 2: Multiple Products
Add multiple products to the products array to include them on the same quote. Each product resolves independently against the Price Book.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Multi-Product Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 5 }
]
}curl:
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": "Multi-Product Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 5 }
]
}'JavaScript fetch:
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Multi-Product Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10 },
{ productSku: "NUE_PLATFORM", uom: "User/Month", quantity: 5 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log(`Total Amount: $${result.quote.totalAmount}`);
console.log(`Line items: ${result.quoteLineItems.length}`); // 2
result.quoteLineItems.forEach(item => {
console.log(` ${item.product.sku}: $${item.totalPrice}`);
});
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Multi-Product Quote",
"totalAmount": 4488.00
},
"quoteLineItems": [
{
"product": { "sku": "NUE_ON_SALESFORCE", "name": "Nue on Salesforce" },
"quantity": 10,
"listPrice": 29.90,
"listTotalPrice": 3588.00,
"totalPrice": 3588.00,
"childrenLineItems": []
},
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 5,
"listPrice": 15.00,
"listTotalPrice": 900.00,
"totalPrice": 900.00,
"childrenLineItems": []
}
]
}The quote totalAmount is the sum of all line item totals: $3,588.00 + $900.00 = $4,488.00.
Use Case 3: Product by Name
If you do not have the product SKU, you can identify a product by its display name using the productName field instead of productSku. The UOM is still required for Price Book Entry resolution.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Name-Based Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productName": "Nue Platform", "uom": "User/Month", "quantity": 10 }
]
}curl:
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": "Name-Based Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productName": "Nue Platform", "uom": "User/Month", "quantity": 10 }
]
}'JavaScript fetch:
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Name-Based Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productName: "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 => {
const line = result.quoteLineItems[0];
console.log(`Resolved SKU: ${line.product.sku}`); // NUE_PLATFORM
console.log(`Product Name: ${line.product.name}`); // Nue Platform
console.log(`Total Price: $${line.totalPrice}`);
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Name-Based Quote",
"totalAmount": 1800.00
},
"quoteLineItems": [
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 10,
"listPrice": 15.00,
"listTotalPrice": 1800.00,
"totalPrice": 1800.00,
"childrenLineItems": []
}
]
}When both productSku and productName are provided, the SKU takes precedence for product resolution.
Use Case 4: Product by SKU
This is the recommended default approach. Identify the product by its unique SKU and provide the UOM to resolve the correct Price Book Entry.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "SKU-Based Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
]
}curl:
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": "SKU-Based Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
]
}'JavaScript fetch:
const quoteData = {
opportunityId: "006xx000001abc123",
name: "SKU-Based Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "NUE_ON_SALESFORCE", 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 => {
const line = result.quoteLineItems[0];
console.log(`SKU: ${line.product.sku}`);
console.log(`Total Price: $${line.totalPrice}`);
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "SKU-Based Quote",
"totalAmount": 3588.00
},
"quoteLineItems": [
{
"product": { "sku": "NUE_ON_SALESFORCE", "name": "Nue on Salesforce" },
"quantity": 10,
"listPrice": 29.90,
"listTotalPrice": 3588.00,
"totalPrice": 3588.00,
"childrenLineItems": []
}
]
}SKU-based identification is preferred because SKUs are unique and stable, whereas product names may change.
Use Case 5: Mixed Revenue Models
A single quote can contain products with different revenue models. Recurring products are priced over the subscription term (ListPrice x Qty x Term), while one-time products are priced as a flat fee (ListPrice x Qty) regardless of term.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Mixed Revenue Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 },
{ "productSku": "IMPLEMENTATION_SERVICE", "uom": "Hour", "quantity": 20 }
]
}curl:
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": "Mixed Revenue Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 },
{ "productSku": "IMPLEMENTATION_SERVICE", "uom": "Hour", "quantity": 20 }
]
}'JavaScript fetch:
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Mixed Revenue Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "NUE_PLATFORM", uom: "User/Month", quantity: 10 },
{ productSku: "IMPLEMENTATION_SERVICE", uom: "Hour", quantity: 20 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log(`Total Amount: $${result.quote.totalAmount}`);
result.quoteLineItems.forEach(item => {
console.log(` ${item.product.sku}: $${item.totalPrice}`);
});
// NUE_PLATFORM: $15.00 x 10 x 12 = $1,800.00 (recurring)
// IMPLEMENTATION_SERVICE: $250.00 x 20 = $5,000.00 (one-time)
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Mixed Revenue Quote",
"totalAmount": 6800.00
},
"quoteLineItems": [
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 10,
"listPrice": 15.00,
"listTotalPrice": 1800.00,
"totalPrice": 1800.00,
"revenueModel": "Recurring",
"childrenLineItems": []
},
{
"product": { "sku": "IMPLEMENTATION_SERVICE", "name": "Implementation Service" },
"quantity": 20,
"listPrice": 250.00,
"listTotalPrice": 5000.00,
"totalPrice": 5000.00,
"revenueModel": "One-Time",
"childrenLineItems": []
}
]
}The recurring product is priced at $15.00 x 10 x 12 = $1,800.00. The one-time product is priced at $250.00 x 20 = $5,000.00 (term is not applied).
Use Case 6: One-Time Products Only
A quote can contain only one-time products. The subscription term fields are still required on the quote header but do not affect one-time pricing.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Professional Services Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "IMPLEMENTATION_SERVICE", "uom": "Hour", "quantity": 40 },
{ "productSku": "UNLIMITED_ONLINE_TRAINING", "uom": "Account", "quantity": 1 },
{ "productSku": "USB_SECURITY_KEY", "uom": "Each", "quantity": 25 }
]
}curl:
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": "Professional Services Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "IMPLEMENTATION_SERVICE", "uom": "Hour", "quantity": 40 },
{ "productSku": "UNLIMITED_ONLINE_TRAINING", "uom": "Account", "quantity": 1 },
{ "productSku": "USB_SECURITY_KEY", "uom": "Each", "quantity": 25 }
]
}'JavaScript fetch:
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Professional Services Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "IMPLEMENTATION_SERVICE", uom: "Hour", quantity: 40 },
{ productSku: "UNLIMITED_ONLINE_TRAINING", uom: "Account", quantity: 1 },
{ productSku: "USB_SECURITY_KEY", uom: "Each", quantity: 25 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log(`Total Amount: $${result.quote.totalAmount}`);
result.quoteLineItems.forEach(item => {
console.log(` ${item.product.sku} (${item.quantity}x): $${item.totalPrice}`);
});
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Professional Services Quote",
"totalAmount": 12625.00
},
"quoteLineItems": [
{
"product": { "sku": "IMPLEMENTATION_SERVICE", "name": "Implementation Service" },
"quantity": 40,
"listPrice": 250.00,
"listTotalPrice": 10000.00,
"totalPrice": 10000.00,
"revenueModel": "One-Time",
"childrenLineItems": []
},
{
"product": { "sku": "UNLIMITED_ONLINE_TRAINING", "name": "Unlimited Online Training" },
"quantity": 1,
"listPrice": 1500.00,
"listTotalPrice": 1500.00,
"totalPrice": 1500.00,
"revenueModel": "One-Time",
"childrenLineItems": []
},
{
"product": { "sku": "USB_SECURITY_KEY", "name": "USB Security Key" },
"quantity": 25,
"listPrice": 45.00,
"listTotalPrice": 1125.00,
"totalPrice": 1125.00,
"revenueModel": "One-Time",
"childrenLineItems": []
}
]
}All three products are one-time: $250 x 40 = $10,000 + $1,500 x 1 = $1,500 + $45 x 25 = $1,125 = $12,625.00 total.
Use Case 7: Duplicate Products
You can include the same SKU multiple times in the products array. Each entry creates a separate line item on the quote. This is useful when you need different quantities, discounts, or configurations for the same product.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Duplicate Product Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 25 }
]
}curl:
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": "Duplicate Product Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Month", "quantity": 25 }
]
}'JavaScript fetch:
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Duplicate Product Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "NUE_PLATFORM", uom: "User/Month", quantity: 10 },
{ productSku: "NUE_PLATFORM", uom: "User/Month", quantity: 25 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log(`Line items: ${result.quoteLineItems.length}`); // 2
result.quoteLineItems.forEach((item, i) => {
console.log(` Line ${i + 1}: ${item.product.sku}, qty=${item.quantity}, $${item.totalPrice}`);
});
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Duplicate Product Quote",
"totalAmount": 6300.00
},
"quoteLineItems": [
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 10,
"listPrice": 15.00,
"listTotalPrice": 1800.00,
"totalPrice": 1800.00,
"childrenLineItems": []
},
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 25,
"listPrice": 15.00,
"listTotalPrice": 4500.00,
"totalPrice": 4500.00,
"childrenLineItems": []
}
]
}The result contains two separate line items, each independently priced. Line 1: $15 x 10 x 12 = $1,800. Line 2: $15 x 25 x 12 = $4,500. Total: $6,300.00.
Response Structure
Each standalone product appears as a top-level entry in the quoteLineItems array:
{
"quote": {
"name": "Single Product Quote",
"totalAmount": 1800.00
},
"quoteLineItems": [
{
"product": {
"sku": "NUE_PLATFORM",
"name": "Nue Platform"
},
"quantity": 10,
"listPrice": 15.00,
"listTotalPrice": 1800.00,
"totalPrice": 1800.00,
"childrenLineItems": []
}
]
}Standalone products have an empty childrenLineItems array. Bundle products, covered in the Bundles guide, populate this array with their bundled and optional components.
Summary
Use Case | Products | Key Concept |
|---|---|---|
1. Single Product | NUE_PLATFORM x 10 | Basic SKU + UOM identification |
2. Multiple Products | NUE_ON_SALESFORCE + NUE_PLATFORM | Multiple products in one quote |
3. Product by Name | productName: "Nue Platform" | Name-based identification |
4. Product by SKU | productSku: "NUE_ON_SALESFORCE" | Preferred identification method |
5. Mixed Revenue | Recurring + One-Time | Different pricing formulas |
6. One-Time Only | Three one-time products | Term does not affect pricing |
7. Duplicate Products | Same SKU, different quantities | Separate line items per entry |