Preview vs Commit
Preview vs Commit
The Nue CPQ Quote API offers two modes for creating quotes: preview (dry-run) and commit (persist). Both modes execute the full pricing engine -- product resolution, bundle expansion, discount propagation, and price tag evaluation -- but differ in whether the result is saved to the database. This guide explains when to use each mode, shows how the request and response differ, and demonstrates the common preview-then-commit pattern.
Overview Comparison
Aspect | Preview | Commit |
|---|---|---|
Endpoint | POST /cpq/quotes:preview | POST /cpq/quotes |
Pricing Calculation | Full pricing engine | Full pricing engine |
Database Writes | None | Quote + line items persisted |
Response quote.id | absent | Real ID |
Request Body | Identical | Identical |
Use Case | Validation, what-if, UI previews | Creating finalized quotes |
Authentication
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: Preview Mode -- Pricing Preview
Preview a quote to see calculated pricing without creating any database records. This is ideal for pricing previews in a UI, what-if analysis, AI-driven validation, and integration testing.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Q1 2026 Enterprise License",
"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": "Q1 2026 Enterprise License",
"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 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 Enterprise License",
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 => {
console.log('Preview result:');
console.log(` quote.id: ${result.quote.id}`); // undefined -- not persisted
console.log(` Total Amount: $${result.quote.totalAmount}`);
console.log(` Line items: ${result.quoteLineItems.length}`);
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"name": "Q1 2026 Enterprise License",
"totalAmount": 3588.00,
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTerm": 12,
"subscriptionTermDimension": "Month"
},
"quoteLineItems": [
{
"product": { "sku": "NUE_ON_SALESFORCE", "name": "Nue on Salesforce" },
"quantity": 10,
"listPrice": 29.90,
"listTotalPrice": 3588.00,
"totalPrice": 3588.00,
"childrenLineItems": []
}
]
}The quote object has no id because nothing was written to the database.
Use Case 2: Commit Mode -- Create a Real Quote
Commit the quote to persist it to the database. The request body is identical to preview; only the endpoint changes.
Request Body:
{
"opportunityId": "006xx000001abc123",
"name": "Q1 2026 Enterprise License",
"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' \
-H 'nue-api-key: YOUR_API_KEY_HERE' \
-H 'Content-Type: application/json' \
-d '{
"opportunityId": "006xx000001abc123",
"name": "Q1 2026 Enterprise License",
"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 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 Enterprise License",
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', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log('Commit result:');
console.log(` quote.id: ${result.quote.id}`); // UUID -- persisted
console.log(` Total Amount: $${result.quote.totalAmount}`);
console.log(` Line items: ${result.quoteLineItems.length}`);
})
.catch(error => console.log('Error:', error));Expected Response:
{
"quote": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Q1 2026 Enterprise License",
"totalAmount": 3588.00,
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTerm": 12,
"subscriptionTermDimension": "Month"
},
"quoteLineItems": [
{
"product": { "sku": "NUE_ON_SALESFORCE", "name": "Nue on Salesforce" },
"quantity": 10,
"listPrice": 29.90,
"listTotalPrice": 3588.00,
"totalPrice": 3588.00,
"childrenLineItems": []
}
]
}The quote.id now contains a UUID. The quote, line items, and all pricing data are persisted.
Use Case 3: Preview-Then-Commit Pattern
A common integration pattern is to preview a quote first, present the pricing to a user or validation system, and then commit only after approval. Because the request body is the same for both endpoints, you can reuse the exact same payload.
Request Body (used for both calls):
{
"opportunityId": "006xx000001abc123",
"name": "Q1 2026 Enterprise License",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"discount": 10,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Year", "quantity": 5 }
]
}curl:
# Step 1: Preview
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 Enterprise License",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"discount": 10,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Year", "quantity": 5 }
]
}'
# Step 2: If approved, commit with the same body
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 Enterprise License",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"discount": 10,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 },
{ "productSku": "NUE_PLATFORM", "uom": "User/Year", "quantity": 5 }
]
}'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: "Q1 2026 Enterprise License",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
discount: 10,
products: [
{ productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10 },
{ productSku: "NUE_PLATFORM", uom: "User/Year", quantity: 5 }
]
};
async function previewThenCommit(quotePayload) {
// Step 1: Preview the quote
const previewResponse = await fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quotePayload)
});
const preview = await previewResponse.json();
console.log('--- Preview ---');
console.log(` quote.id: ${preview.quote.id}`); // undefined
console.log(` Total Amount: $${preview.quote.totalAmount}`);
console.log(` Line items: ${preview.quoteLineItems.length}`);
// Step 2: Validate or present to user
const totalAmount = preview.quote.totalAmount;
if (totalAmount > 50000) {
console.log('Quote exceeds $50,000 -- requires manager approval.');
return preview;
}
// Step 3: Commit the same payload
const commitResponse = await fetch('https://api.nue.io/cpq/quotes', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quotePayload)
});
const committed = await commitResponse.json();
console.log('--- Committed ---');
console.log(` quote.id: ${committed.quote.id}`); // UUID
console.log(` Total Amount: $${committed.quote.totalAmount}`);
return committed;
}
previewThenCommit(quoteData)
.then(result => console.log('Done.'))
.catch(error => console.log('Error:', error));Expected Preview Response:
{
"quote": {
"name": "Q1 2026 Enterprise License",
"totalAmount": 3674.70,
"discount": 10
},
"quoteLineItems": [
{
"product": { "sku": "NUE_ON_SALESFORCE", "name": "Nue on Salesforce" },
"quantity": 10,
"listTotalPrice": 3588.00,
"discount": 10,
"totalPrice": 3229.20
},
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 5,
"listTotalPrice": 495.00,
"discount": 10,
"totalPrice": 445.50
}
]
}Expected Commit Response:
{
"quote": {
"id": "f7e8d9c0-b1a2-3456-cdef-789012345678",
"name": "Q1 2026 Enterprise License",
"totalAmount": 3674.70,
"discount": 10
},
"quoteLineItems": [
{
"product": { "sku": "NUE_ON_SALESFORCE", "name": "Nue on Salesforce" },
"quantity": 10,
"listTotalPrice": 3588.00,
"discount": 10,
"totalPrice": 3229.20
},
{
"product": { "sku": "NUE_PLATFORM", "name": "Nue Platform" },
"quantity": 5,
"listTotalPrice": 495.00,
"discount": 10,
"totalPrice": 445.50
}
]
}The only difference between the two responses is the quote.id field.
Behavior Comparison
Behavior | Preview | Commit |
|---|---|---|
Product resolution | Full | Full |
Bundle expansion | Full | Full |
Pricing engine | Full calculation | Full calculation |
Discount propagation | Full | Full |
Price tag evaluation | Full | Full |
Database writes | None | Quote + all line items persisted |
quote.id in response | absent | present |
Idempotency | Fully idempotent (no side effects) | Creates a new quote each call |
Downstream triggers | None | May trigger workflows, notifications |
When to Use Each Mode
Scenario | Mode | Why |
|---|---|---|
Price calculator UI | Preview | No database clutter from exploratory pricing |
AI agent building a quote | Preview first, then Commit | Validate pricing before persisting |
Batch quote generation | Commit | Directly persist finalized quotes |
What-if comparisons | Preview | Run multiple scenarios without side effects |
Integration testing | Preview | Validate API integration without creating records |
Final quote creation | Commit | Persist the approved quote for downstream processing |
Key Takeaways
- The request body is identical for both endpoints -- only the URL differs.
- Preview runs the full pricing engine but does not persist anything.
- Commit runs the same pricing engine and saves the result to the database.
- Use the preview-then-commit pattern to validate before persisting.
- In preview mode the quote object has no id, and line items carry temp_<uuid> ids. In commit mode both carry real ids.