Invoice Preview
This guide covers the Invoice Preview endpoint (POST /orders/invoice-preview), which computes invoice data for both initial orders and change orders without persisting any data. Use it to show customers what they will be billed before committing to an order.
Prerequisites
Before you begin, ensure you have:
- A valid Nue API key with order permissions
- For initial order previews: a customer ID and price book entry IDs
- For change order previews: asset numbers (SUB-XXXXXX format) for existing subscriptions
- Basic knowledge of REST APIs and JSON
Single Endpoint, Two Modes
The invoice preview endpoint handles both initial orders and change orders through a single POST /orders/invoice-preview call. The request body determines which mode is used:
- Include orderProducts for an initial order preview
- Include assetChanges for a change order preview
You cannot include both in the same request.
Authentication
All invoice preview requests require authentication using your Nue API key in the nue-api-key header:
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");Key Behaviors
Behavior | Details |
|---|---|
Zero persistence | The endpoint computes invoices entirely in-memory. No orders, subscriptions, or invoices are written to the database. |
Initial order preview | Provide orderProducts to preview invoices for a new order. Uses the same pricing engine as POST /orders. |
Change order preview | Provide assetChanges to preview invoices for modifications to existing subscriptions. Uses the same pricing engine as POST /change-orders. |
Mutual exclusivity | Exactly one of orderProducts or assetChanges must be present. Sending both returns a validation error. |
Tax | Tax calculation is not supported on invoice previews. To obtain tax amounts, create a draft order via POST /orders instead. |
Forbidden options | The options generateInvoice, activateInvoice, and asyncPayment are rejected with an error if set to true. These are execution-time flags that do not apply to previews. |
Initial Order Invoice Preview
Preview invoices for a new order by providing orderProducts. The request body accepts the same product fields as POST /orders (see Create Draft OrdersCreate Draft Orders).
Basic Example
Preview the invoice for a single product subscription:
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
const previewRequest = {
customer: {
id: "d2e04653-ae90-49df-a986-134cf64f6d03"
},
effectiveDate: "2025-07-01",
orderProducts: [
{
priceBookEntryId: "01uQL000009Tsn7YAC",
quantity: 10,
subscriptionStartDate: "2025-07-01",
subscriptionTerm: 12
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
console.log('Invoice preview:', result);
if (result.previewInvoices && result.previewInvoices.length > 0) {
const invoice = result.previewInvoices[0];
console.log(`Invoice Amount: $${invoice.amount}`);
console.log(`Start Date: ${invoice.startDate}`);
console.log(`End Date: ${invoice.endDate}`);
// Iterate invoice line items
invoice.items.forEach(item => {
console.log(` ${item.productName}: $${item.amount}`);
});
}
})
.catch(error => console.log('Error:', error));Multiple Products
Preview invoices for multiple products:
const previewRequest = {
customer: {
id: "d2e04653-ae90-49df-a986-134cf64f6d03"
},
effectiveDate: "2025-07-01",
orderProducts: [
{
priceBookEntryId: "01uQL000009Tsn7YAC",
quantity: 10,
subscriptionStartDate: "2025-07-01",
subscriptionTerm: 12
},
{
priceBookEntryId: "01uQL000009Tsn8YAC",
quantity: 5,
subscriptionStartDate: "2025-07-01",
subscriptionTerm: 12
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
if (result.previewInvoices) {
result.previewInvoices.forEach(invoice => {
console.log(`Amount: $${invoice.amount}`);
console.log(`Start: ${invoice.startDate}`);
console.log(`End: ${invoice.endDate}`);
});
}
})
.catch(error => console.log('Error:', error));Bundle Products
Bundles work the same as in POST /orders — specify add-ons for optional bundle components:
const previewRequest = {
customer: {
id: "d2e04653-ae90-49df-a986-134cf64f6d03"
},
effectiveDate: "2025-07-01",
orderProducts: [
{
priceBookEntryId: "01uQL000009BundleABC",
quantity: 10,
subscriptionStartDate: "2025-07-01",
subscriptionTerm: 12,
addOns: [
{
productOptionId: "opt_IMPL_SERVICE",
productOptionQuantity: 20
}
]
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
console.log('Bundle invoice preview:', result.previewInvoices);
})
.catch(error => console.log('Error:', error));Change Order Invoice Preview
Preview invoices for changes to existing subscriptions by providing assetChanges. The request body accepts the same change fields as POST /change-orders (see Creating Draft Change OrdersCreating Draft Change Orders).
Quantity Update
Preview the billing impact of adding seats to an existing subscription:
const previewRequest = {
assetChanges: [
{
changeType: "UpdateQuantity",
assetNumber: "SUB-00003725",
quantity: 25,
startDate: "2025-07-15"
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
if (result.previews && result.previews.length > 0) {
const preview = result.previews[0];
console.log(`Asset: ${preview.assetNumber}`);
const summary = preview.priceSummary;
console.log(`Today's Charge: $${summary.todayChargePrice}`);
console.log(`Next Billing Period: $${summary.nextBillingPeriodPrice}`);
console.log(`Next Billing Date: ${summary.nextBillingDate}`);
const asset = preview.previewResult;
console.log(`New Quantity: ${asset.quantity}`);
console.log(`Start Date: ${asset.startDate}`);
console.log(`End Date: ${asset.endDate}`);
}
})
.catch(error => console.log('Error:', error));Renewal
Preview the invoice for renewing a subscription:
const previewRequest = {
assetChanges: [
{
changeType: "Renew",
assetNumber: "SUB-00003725",
renewalTerm: 12
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
if (result.previews) {
const preview = result.previews[0];
console.log(`Total Price: $${preview.priceSummary.totalPrice}`);
console.log(`New End Date: ${preview.previewResult.endDate}`);
}
})
.catch(error => console.log('Error:', error));Upgrade
Preview the cost of upgrading to a higher-tier product:
const previewRequest = {
assetChanges: [
{
changeType: "Upgrade",
assetNumber: "SUB-00003725",
targetPriceBookEntryId: "01uEm00000CNoaXIAT",
startDate: "2025-07-15"
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
if (result.previews) {
const preview = result.previews[0];
console.log(`Today's Charge: $${preview.priceSummary.todayChargePrice}`);
console.log(`Next Period: $${preview.priceSummary.nextBillingPeriodPrice}`);
}
})
.catch(error => console.log('Error:', error));Cancellation
Preview any remaining charges or credits for cancelling a subscription:
const previewRequest = {
assetChanges: [
{
changeType: "Cancel",
assetNumber: "SUB-00003725",
cancellationDate: "2025-08-01"
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
if (result.previews) {
const preview = result.previews[0];
console.log(`Cancellation Date: ${preview.previewResult.cancellationDate}`);
console.log(`Today's Charge: $${preview.priceSummary.todayChargePrice}`);
}
})
.catch(error => console.log('Error:', error));Cross-Sell (New Products on Change Order)
Add new products alongside changes to existing subscriptions. The products array requires at least one accompanying entry in assetChanges:
const previewRequest = {
assetChanges: [
{
changeType: "Renew",
assetNumber: "SUB-00003725",
renewalTerm: 12
}
],
products: [
{
priceBookEntryId: "01uQL000009Tsn8YAC",
quantity: 5,
subscriptionStartDate: "2025-07-01",
subscriptionTerm: 12
}
]
};
fetch('https://api.nue.io/orders/invoice-preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(previewRequest)
})
.then(response => response.json())
.then(result => {
console.log('Change order + cross-sell preview:', result.previews);
})
.catch(error => console.log('Error:', error));Request Reference
Top-Level Fields
Field | Type | Required | Description |
|---|---|---|---|
customer | object | Yes (initial order) | Customer placing the order. Must contain an id field. |
effectiveDate | string | No | Effective date in YYYY-MM-DD format. Used for initial order previews. |
orderProducts | array | Yes (initial order) | Product lines for an initial order preview. Same schema as POST /orders. |
assetChanges | array | Yes (change order) | Asset changes for a change order preview. Same schema as POST /change-orders. |
products | array | No | New products to add alongside a change order (cross-sell). Requires assetChanges. |
billingPeriod | string | No | Billing period for the order. |
billingAccountId | string | No | Billing account ID. |
description | string | No | Order description. |
customFields | object | No | Custom fields for the order. |
timeZone | string | No | Time zone for date calculations (change orders). |
poNumber | string | No | Purchase order number. |
poDate | string | No | Purchase order date in YYYY-MM-DD format. |
Forbidden Options
The following options are rejected with an error if set to true: generateInvoice, activateInvoice, asyncPayment. These are execution-time flags that do not apply to previews.
Validation Rules
Rule | Error |
|---|---|
Both orderProducts and assetChanges provided | INVOICE_PREVIEW_INVALID_PAYLOAD |
Both orderProducts and products provided | INVOICE_PREVIEW_INVALID_PAYLOAD |
products provided without assetChanges | CHANGE_TYPE_COMBINATION_REQUIRED |
Neither orderProducts nor assetChanges provided | INVOICE_PREVIEW_MISSING_BODY |
Response Reference
The response shape depends on whether you submitted an initial order or change order preview.
Initial Order Response
For orderProducts requests, the response contains previewInvoices:
Field | Type | Description |
|---|---|---|
previewInvoices | array | List of computed invoice objects. |
previewInvoices[].amount | number | Total invoice amount. |
previewInvoices[].amountWithoutTax | number | Invoice subtotal amount. |
previewInvoices[].invoiceDate | string | Invoice date. |
previewInvoices[].dueDate | string | Payment due date. |
previewInvoices[].startDate | string | Billing period start date. |
previewInvoices[].endDate | string | Billing period end date. |
previewInvoices[].currencyIsoCode | string | ISO currency code. |
previewInvoices[].items | array | Invoice line items with per-product billing detail. |
Change Order Response
For assetChanges requests, the response contains previews:
Field | Type | Description |
|---|---|---|
previews | array | List of per-asset preview objects. |
previews[].assetNumber | string | The subscription asset number. |
previews[].priceSummary | object | Aggregated billing summary (see below). |
previews[].previewResult | object | Updated asset state after the change (see below). |
previews[].previewRequest | object | Echo of the original change request for this asset. |
Price Summary
Field | Type | Description |
|---|---|---|
totalPrice | number | Total price across all billing periods. |
totalAmount | number | Total amount across all periods. |
todayChargePrice | number | Immediate charge price (prorated for mid-cycle changes). |
todayChargeAmount | number | Immediate charge amount. |
nextBillingPeriodPrice | number | Price for the next full billing period. |
nextBillingPeriodAmount | number | Amount for the next billing period. |
nextBillingDate | string | Date of the next billing cycle. |
Preview Result
Field | Type | Description |
|---|---|---|
assetNumber | string | Subscription asset number. |
quantity | number | Quantity after the change. |
term | number | Term after the change. |
startDate | string | Subscription start date. |
endDate | string | Subscription end date after the change. |
cancellationDate | string | Cancellation effective date (Cancel changes only). |
orderPrice | object | Order-level pricing detail. |
billingPrice | object | Billing-level pricing detail. |
changes | array | Itemized list of changes applied. |
childrenAssets | array | Child asset previews for bundle subscriptions. |