Discounts
Discounts
The Nue CPQ pricing engine supports a three-layer discount model that gives you precise control over how discounts are applied across a quote. Discounts can be set at the header level, the parent/bundle level, or the individual line-item level, and they follow deterministic override rules so you always know which discount wins.
Use this guide when you need to apply discretionary discounts to new quotes -- whether a blanket percentage across all lines, targeted discounts on specific products, dollar-amount discounts, or combinations of these.
Discount Layers
Layer | Field Location | Applies To | Override Behavior |
|---|---|---|---|
Header discount | discount or discountAmount on the quote root | All line items that do not have their own discount | Lowest priority; overridden by bundle or product-level discounts |
Bundle/Parent discount | discount or discountAmount on a bundle product | All children of that bundle (unless child has its own) | Middle priority; overrides header, overridden by child-level |
Line-level discount | discount or discountAmount on a product entry | That specific line item only | Highest priority; overrides header and parent discounts |
Key Rules
- Percentage takes priority over amount. If both discount (percentage) and discountAmount are provided on the same object, the percentage value is used and the amount is ignored.
- Product-level discount overrides header discount. A line item with its own discount or discountAmount will not receive the header-level discount.
- Bundle discount propagates to children. A discount on a bundle parent flows down to all child add-ons unless the child specifies its own discount.
- Header discountAmount is distributed proportionally. The fixed dollar amount is allocated across eligible lines based on each line's share of the total list amount.
- Bundled items with a $0 list price are not discountable. Discounts are skipped for zero-price children.
- Non-discountable products generate a warning. If a product is configured as non-discountable in the catalog, the system issues a warning and skips the discount for that line.
Pricing Calculation Order
- Resolve the list unit price from the Price Book Entry (or price tag).
- Apply price tags (PriceDimension) to determine the effective unit price.
- Apply discount tags (DiscountDimension) if present.
- Apply discretionary discounts (this guide) -- header, bundle, or line-level.
- Calculate the final totalPrice for each line.
Warning Codes
Warning Code | Meaning |
|---|---|
PRODUCT_DISCOUNT_OVERRIDES_HEADER | A product-level discount was found, so the header discount was not applied to that line |
PRODUCT_DISCOUNT_APPLIED | A product-level discount was successfully applied |
HEADER_DISCOUNT_APPLIED | The header discount was applied to a line that had no product-level override |
PRODUCT_NOT_DISCOUNTABLE | The product is configured as non-discountable; the discount was skipped |
Authentication Setup
All examples below use the following headers:
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");Use Case 1: Header-Level Percentage Discount
Apply a 10% discount to every line item in the quote by setting discount on the quote root. The discount propagates to all lines that do not have their own product-level discount.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Q1 Enterprise License — 10% Header Discount",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
discount: 10,
products: [
{ productSku: "PLATFORM_BASE", uom: "User/Month", quantity: 50 },
{ productSku: "ANALYTICS_ADDON", uom: "User/Month", quantity: 50 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log(`Header discount: ${result.quote.discount}%`);
result.quoteLineItems.forEach(item => {
console.log(`${item.product.sku}: list $${item.listTotalPrice} → total $${item.totalPrice} (${item.discount}% off)`);
});
})
.catch(error => console.log('Error:', error));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 Enterprise License — 10% Header Discount",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"discount": 10,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 50 }
]
}'Both products receive the 10% discount because neither has a product-level discount override. The response warnings array will contain HEADER_DISCOUNT_APPLIED entries for each line.
Use Case 2: Product-Level Discount on Bundle and Standalone
Apply different discounts to a bundle parent (20%) and a standalone product (10%). The bundle's 20% discount propagates to all of its child add-ons.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Bundle 20% + Standalone 10%",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{
productSku: "ENTERPRISE_SUITE",
uom: "User/Month",
quantity: 50,
discount: 20,
addOns: [
{ productSku: "PREMIUM_SUPPORT", uom: "User/Month", quantity: 50 },
{ productSku: "DATA_EXPORT", uom: "User/Month", quantity: 50 }
]
},
{ productSku: "ANALYTICS_ADDON", uom: "User/Month", quantity: 25, discount: 10 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
result.quoteLineItems.forEach(item => {
console.log(`${item.product.sku}: ${item.discount}% off → $${item.totalPrice}`);
if (item.childrenLineItems) {
item.childrenLineItems.forEach(child => {
console.log(` └─ ${child.product.sku}: ${child.discount}% off → $${child.totalPrice}`);
});
}
});
})
.catch(error => console.log('Error:', error));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": "Bundle 20% + Standalone 10%",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{
"productSku": "ENTERPRISE_SUITE",
"uom": "User/Month",
"quantity": 50,
"discount": 20,
"addOns": [
{ "productSku": "PREMIUM_SUPPORT", "uom": "User/Month", "quantity": 50 },
{ "productSku": "DATA_EXPORT", "uom": "User/Month", "quantity": 50 }
]
},
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 25, "discount": 10 }
]
}'Result:
- ENTERPRISE_SUITE parent and both children (PREMIUM_SUPPORT, DATA_EXPORT) receive 20% off.
- ANALYTICS_ADDON receives its own 10% discount independently.
Use Case 3: Bundle Discount with Protected Add-On
Apply a 15% discount to a bundle parent, but protect a specific add-on from the discount by setting discount: 0 on it. The protected add-on keeps its full list price while sibling add-ons inherit the parent discount.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Bundle 15% with Protected Add-On",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{
productSku: "ENTERPRISE_SUITE",
uom: "User/Month",
quantity: 50,
discount: 15,
addOns: [
{ productSku: "PREMIUM_SUPPORT", uom: "User/Month", quantity: 50 },
{ productSku: "DATA_EXPORT", uom: "User/Month", quantity: 50, discount: 0 }
]
}
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
const parent = result.quoteLineItems[0];
console.log(`${parent.product.sku}: ${parent.discount}% off`);
parent.childrenLineItems.forEach(child => {
console.log(` └─ ${child.product.sku}: ${child.discount}% off → $${child.totalPrice}`);
});
// PREMIUM_SUPPORT inherits 15% from parent
// DATA_EXPORT uses its own 0% discount (full price)
})
.catch(error => console.log('Error:', error));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": "Bundle 15% with Protected Add-On",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{
"productSku": "ENTERPRISE_SUITE",
"uom": "User/Month",
"quantity": 50,
"discount": 15,
"addOns": [
{ "productSku": "PREMIUM_SUPPORT", "uom": "User/Month", "quantity": 50 },
{ "productSku": "DATA_EXPORT", "uom": "User/Month", "quantity": 50, "discount": 0 }
]
}
]
}'Result:
- ENTERPRISE_SUITE and PREMIUM_SUPPORT receive 15% off.
- DATA_EXPORT receives 0% off (its own discount: 0 overrides the parent's 15%). The response warnings will include PRODUCT_DISCOUNT_OVERRIDES_HEADER for DATA_EXPORT.
Use Case 4: Dollar Discount Amount on a Product
Apply a fixed dollar discount (discountAmount) to a specific product instead of a percentage. The discountAmount is subtracted from the line's list total price.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Dollar Discount on Product",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "PLATFORM_BASE", uom: "User/Month", quantity: 10, discountAmount: 50 },
{ productSku: "ANALYTICS_ADDON", 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 => {
result.quoteLineItems.forEach(item => {
console.log(`${item.product.sku}: list $${item.listTotalPrice}, discountAmount $${item.discountAmount || 0}, total $${item.totalPrice}`);
});
})
.catch(error => console.log('Error:', error));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": "Dollar Discount on Product",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 10, "discountAmount": 50 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 10 }
]
}'PLATFORM_BASE has $50 subtracted from its list total price. ANALYTICS_ADDON receives no discount because neither a header nor product-level discount is specified.
Use Case 5: Header Dollar Amount + Product Percentage (Mixed)
Combine a header-level discountAmount with a product-level discount percentage. The product with its own percentage discount uses that value; lines without a product-level discount receive a proportional share of the header dollar amount.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Header Dollar + Product Percentage Mix",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
discountAmount: 200,
products: [
{ productSku: "PLATFORM_BASE", uom: "User/Month", quantity: 50 },
{ productSku: "ANALYTICS_ADDON", uom: "User/Month", quantity: 50, discount: 15 },
{ productSku: "DATA_EXPORT", 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(`Header discountAmount: $${result.quote.discountAmount}`);
result.quoteLineItems.forEach(item => {
console.log(`${item.product.sku}: discount=${item.discount || 0}%, discountAmount=$${item.discountAmount || 0}, total=$${item.totalPrice}`);
});
// PLATFORM_BASE: receives proportional share of the $200 header amount
// ANALYTICS_ADDON: receives its own 15% discount (header dollar skipped)
// DATA_EXPORT: receives proportional share of the $200 header amount
})
.catch(error => console.log('Error:', error));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": "Header Dollar + Product Percentage Mix",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"discountAmount": 200,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 50, "discount": 15 },
{ "productSku": "DATA_EXPORT", "uom": "User/Month", "quantity": 25 }
]
}'Result:
- ANALYTICS_ADDON uses its own 15% percentage discount. The header discountAmount is not applied to this line.
- PLATFORM_BASE and DATA_EXPORT split the $200 header discount proportionally based on their list amounts. The warnings array will include PRODUCT_DISCOUNT_OVERRIDES_HEADER for ANALYTICS_ADDON.
Use Case 6: Non-Discountable Products
When a product is configured as non-discountable in the product catalog, the pricing engine skips the discount for that line and issues a warning. Other eligible lines still receive their discounts.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Quote with Non-Discountable Product",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
discount: 10,
products: [
{ productSku: "PLATFORM_BASE", uom: "User/Month", quantity: 50 },
{ productSku: "COMPLIANCE_MODULE", uom: "User/Month", quantity: 50 },
{ productSku: "ANALYTICS_ADDON", 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 => {
result.quoteLineItems.forEach(item => {
console.log(`${item.product.sku}: discount=${item.discount || 0}%, total=$${item.totalPrice}`);
});
// No warnings array is returned -- read each line's discount to see what
// the engine applied. A non-discountable product simply comes back at full
// price, while PLATFORM_BASE and ANALYTICS_ADDON take the 10% header discount.
})
.catch(error => console.log('Error:', error));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": "Quote with Non-Discountable Product",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"discount": 10,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 },
{ "productSku": "COMPLIANCE_MODULE", "uom": "User/Month", "quantity": 50 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 25 }
]
}'Result:
- PLATFORM_BASE and ANALYTICS_ADDON receive the 10% header discount normally.
- COMPLIANCE_MODULE is non-discountable: its totalPrice equals its listTotalPrice, and the response warnings array contains a PRODUCT_NOT_DISCOUNTABLE entry for that line.
Discount Interaction Rules
Scenario | Behavior |
|---|---|
Header discount + no product discount | Header percentage applied to all lines |
Header discount + product discount | Product percentage wins; header skipped for that line |
Header discountAmount + no product discount | Dollar amount distributed proportionally across all lines |
Header discountAmount + product discount | Product percentage wins; header dollar excluded from that line's allocation |
Bundle discount + no child discount | Bundle percentage propagates to all children |
Bundle discount + child discount | Child percentage wins; bundle discount skipped for that child |
Both discount and discountAmount on same object | Percentage wins; dollar amount ignored |
Non-discountable product + any discount | Discount skipped; warning issued |
Discount Field Reference
Field | Type | Scope | Description |
|---|---|---|---|
discount | number (0-100) | Quote root, Product, Add-on | Percentage discount |
discountAmount | number | Quote root, Product, Add-on | Fixed dollar discount |
Next Steps
- Price Tags -- Apply tiered, volume, and ramp pricing adjustments
- Subscription Terms -- Configure term lengths, billing periods, and renewal settings
- Bundles -- Work with bundle products and add-ons
- Create Quote Overview -- Return to the full API reference