Subscription Terms
Subscription Terms
Subscription terms control the duration, billing cadence, renewal behavior, and date calculations for recurring products on a quote. This guide covers all common term configurations, from standard annual subscriptions to evergreen contracts and backdated quotes.
Use this guide when you need to configure subscription start and end dates, term lengths, billing periods, auto-renewal, or per-product term overrides.
Term Calculation Rules
The pricing engine requires any two of the following three values to calculate the third:
Provided | Calculated | Rule |
|---|---|---|
subscriptionStartDate + subscriptionTerm | subscriptionEndDate | End date = start date + term |
subscriptionStartDate + subscriptionEndDate | subscriptionTerm | Term = difference between dates in the specified dimension |
subscriptionEndDate + subscriptionTerm | subscriptionStartDate | Start date = end date - term |
If all three are provided, the engine uses the start date and term to verify the end date.
Date Conventions
- All dates use ISO 8601 format: YYYY-MM-DD (e.g., 2025-01-01).
- The subscriptionTermDimension field specifies the unit for the term value. Valid values: "Month", "Year", "Day".
- When subscriptionTermDimension is "Month", a subscriptionTerm of 12 equals one year.
Billing Configuration Fields
Field | Type | Valid Values | Default | Description |
|---|---|---|---|---|
billingPeriod | string | "Monthly", "Quarterly", "Semi-Annual", "Annual" | Inherited from product | How often the customer is invoiced |
billingTiming | string | "In Advance", "In Arrears" | Inherited from product | Whether billing occurs at the start or end of each period |
autoRenew | boolean | true, false | false | Whether the subscription automatically renews at end of term |
renewalTerm | number | Any positive integer | Same as subscriptionTerm | The term length for each renewal period |
evergreen | boolean | true, false | false | Whether the subscription continues indefinitely with no fixed end date |
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: Standard 12-Month Term
The most common configuration: a 12-month subscription with explicit start date, end date, and term.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Standard Annual Subscription",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "PLATFORM_BASE", 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(`Start: ${result.quote.subscriptionStartDate}`);
console.log(`End: ${result.quote.subscriptionEndDate}`);
console.log(`Term: ${result.quote.subscriptionTerm} months`);
console.log(`Total: $${result.quote.totalAmount}`);
})
.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": "Standard Annual Subscription",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 }
]
}'The pricing engine calculates: listUnitPrice * quantity * 12 months.
Use Case 2: 24-Month Term with Future Start Date
Create a subscription that starts 3 months in the future with a 24-month term. The end date is calculated automatically.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "24-Month Future Start",
subscriptionStartDate: "2025-04-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 24,
products: [
{ productSku: "PLATFORM_BASE", uom: "User/Month", quantity: 100 }
]
};
fetch('https://api.nue.io/cpq/quotes:preview', {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(quoteData)
})
.then(response => response.json())
.then(result => {
console.log(`Start: ${result.quote.subscriptionStartDate}`); // 2025-04-01
console.log(`End: ${result.quote.subscriptionEndDate}`); // 2027-04-01 (calculated)
console.log(`Term: ${result.quote.subscriptionTerm} months`); // 24
console.log(`Total: $${result.quote.totalAmount}`);
})
.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": "24-Month Future Start",
"subscriptionStartDate": "2025-04-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 24,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 100 }
]
}'By providing only subscriptionStartDate and subscriptionTerm, the pricing engine calculates subscriptionEndDate as 2027-04-01.
Use Case 3: Short-Term Subscriptions (3 and 6 Months)
Create short-term subscriptions by specifying a lower subscriptionTerm. Multiple products can share the same term.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Short-Term 6-Month Trial",
subscriptionStartDate: "2025-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 6,
products: [
{ productSku: "PLATFORM_BASE", uom: "User/Month", quantity: 25 },
{ 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 => {
console.log(`Term: ${result.quote.subscriptionTerm} months`);
console.log(`End: ${result.quote.subscriptionEndDate}`); // 2025-07-01 (calculated)
console.log(`Total: $${result.quote.totalAmount}`);
// Pricing reflects 6 months, not 12
})
.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": "Short-Term 6-Month Trial",
"subscriptionStartDate": "2025-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 6,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 25 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 25 }
]
}'The total reflects 6 months of recurring charges rather than 12. The calculated end date is 2025-07-01.
Use Case 4: Per-Product Term Overrides
Different products on the same quote can have different subscription terms. Set subscriptionTerm, subscriptionStartDate, and subscriptionEndDate at the product level to override the quote-level values.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Mixed Term Lengths",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{
productSku: "PLATFORM_BASE",
uom: "User/Month",
quantity: 50
// Inherits quote-level: 12-month term, 2025-01-01 to 2026-01-01
},
{
productSku: "ANALYTICS_ADDON",
uom: "User/Month",
quantity: 50,
subscriptionTerm: 6,
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2025-07-01"
// Override: 6-month term for this product only
},
{
productSku: "PREMIUM_SUPPORT",
uom: "User/Month",
quantity: 50,
subscriptionTerm: 24,
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2027-01-01"
// Override: 24-month term for this product only
}
]
};
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}: term=${item.subscriptionTerm}mo, $${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": "Mixed Term Lengths",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 },
{
"productSku": "ANALYTICS_ADDON",
"uom": "User/Month",
"quantity": 50,
"subscriptionTerm": 6,
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2025-07-01"
},
{
"productSku": "PREMIUM_SUPPORT",
"uom": "User/Month",
"quantity": 50,
"subscriptionTerm": 24,
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2027-01-01"
}
]
}'Result:
- PLATFORM_BASE: 12-month term (inherited from quote header).
- ANALYTICS_ADDON: 6-month term (product-level override).
- PREMIUM_SUPPORT: 24-month term (product-level override).
Each line item's totalPrice reflects its own term length.
Use Case 5: Auto-Renew Configuration
Enable automatic renewal by setting autoRenew: true on the quote. Optionally specify a renewalTerm for the renewal period length. If renewalTerm is not provided, it defaults to the original subscriptionTerm.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Auto-Renewing Annual Subscription",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
autoRenew: true,
renewalTerm: 12,
products: [
{ productSku: "PLATFORM_BASE", 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 => {
console.log(`Auto-renew: ${result.quote.autoRenew}`); // true
console.log(`Renewal term: ${result.quote.renewalTerm} months`); // 12
console.log(`Total (initial term): $${result.quote.totalAmount}`);
})
.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": "Auto-Renewing Annual Subscription",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"autoRenew": true,
"renewalTerm": 12,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 25 }
]
}'The quote is priced for the initial 12-month term. The autoRenew and renewalTerm values are stored on the resulting subscription and control automatic renewal behavior at the end of the initial term.
Use Case 6: Billing Period and Timing Overrides
Override the default billing period and timing at the quote level. These values apply to all products unless overridden at the product level.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Monthly In-Advance Billing",
subscriptionStartDate: "2025-01-01",
subscriptionEndDate: "2026-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
billingPeriod: "Monthly",
billingTiming: "In Advance",
products: [
{ productSku: "PLATFORM_BASE", 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 => {
console.log(`Billing period: ${result.quote.billingPeriod}`); // Monthly
console.log(`Billing timing: ${result.quote.billingTiming}`); // In Advance
console.log(`Total: $${result.quote.totalAmount}`);
result.quoteLineItems.forEach(item => {
console.log(`${item.product.sku}: billingPeriod=${item.billingPeriod}, billingTiming=${item.billingTiming}`);
});
})
.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": "Monthly In-Advance Billing",
"subscriptionStartDate": "2025-01-01",
"subscriptionEndDate": "2026-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"billingPeriod": "Monthly",
"billingTiming": "In Advance",
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 },
{ "productSku": "ANALYTICS_ADDON", "uom": "User/Month", "quantity": 25 }
]
}'Both products inherit the quote-level billingPeriod and billingTiming. The total amount is the same regardless of billing period -- billing period affects invoice scheduling, not the quote total.
Use Case 7: Evergreen Subscriptions
An evergreen subscription has no fixed end date. It continues indefinitely until explicitly canceled. Set evergreen: true on the quote. When evergreen is enabled, subscriptionEndDate and subscriptionTerm are not required.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Evergreen Subscription",
subscriptionStartDate: "2025-01-01",
subscriptionTermDimension: "Month",
evergreen: true,
billingPeriod: "Monthly",
products: [
{ productSku: "PLATFORM_BASE", 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(`Evergreen: ${result.quote.evergreen}`); // true
console.log(`End date: ${result.quote.subscriptionEndDate}`); // null or not set
console.log(`Total: $${result.quote.totalAmount}`);
// Total is typically calculated for one billing period
})
.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": "Evergreen Subscription",
"subscriptionStartDate": "2025-01-01",
"subscriptionTermDimension": "Month",
"evergreen": true,
"billingPeriod": "Monthly",
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 }
]
}'Use Case 8: Term Calculation from Dates
Provide only subscriptionStartDate and subscriptionEndDate and let the pricing engine calculate the term automatically. This is useful when the business requirement is defined by calendar dates rather than a fixed number of months.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Date-Driven Term Calculation",
subscriptionStartDate: "2025-03-15",
subscriptionEndDate: "2026-09-15",
subscriptionTermDimension: "Month",
products: [
{ productSku: "PLATFORM_BASE", 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(`Start: ${result.quote.subscriptionStartDate}`); // 2025-03-15
console.log(`End: ${result.quote.subscriptionEndDate}`); // 2026-09-15
console.log(`Calculated term: ${result.quote.subscriptionTerm} months`); // 18
console.log(`Total: $${result.quote.totalAmount}`);
})
.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": "Date-Driven Term Calculation",
"subscriptionStartDate": "2025-03-15",
"subscriptionEndDate": "2026-09-15",
"subscriptionTermDimension": "Month",
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 }
]
}'The pricing engine calculates the term as 18 months (from March 15, 2025 to September 15, 2026) and prices accordingly.
Use Case 9: Backdated Quotes
Create a quote with a start date in the past. This is useful for retroactive contracts or late-entry deals. The pricing engine calculates the term and total based on the provided dates regardless of the current calendar date.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Backdated Quote",
subscriptionStartDate: "2024-10-01",
subscriptionEndDate: "2025-10-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
products: [
{ productSku: "PLATFORM_BASE", 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(`Start: ${result.quote.subscriptionStartDate}`); // 2024-10-01 (in the past)
console.log(`End: ${result.quote.subscriptionEndDate}`); // 2025-10-01
console.log(`Term: ${result.quote.subscriptionTerm} months`); // 12
console.log(`Total: $${result.quote.totalAmount}`);
})
.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": "Backdated Quote",
"subscriptionStartDate": "2024-10-01",
"subscriptionEndDate": "2025-10-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "PLATFORM_BASE", "uom": "User/Month", "quantity": 50 }
]
}'The pricing engine does not reject past start dates. The full 12-month term is priced normally. Downstream billing and invoicing systems handle proration or catch-up invoices for the elapsed period.
Term and Billing Field Reference
Field | Type | Scope | Description |
|---|---|---|---|
subscriptionStartDate | string (ISO date) | Quote root, Product | Start date of the subscription |
subscriptionEndDate | string (ISO date) | Quote root, Product | End date of the subscription |
subscriptionTerm | number | Quote root, Product | Duration of the subscription in the specified dimension |
subscriptionTermDimension | string | Quote root | Unit for the term: "Month", "Year", or "Day" |
billingPeriod | string | Quote root, Product | Invoice frequency: "Monthly", "Quarterly", "Semi-Annual", "Annual" |
billingTiming | string | Quote root, Product | When to bill: "In Advance" or "In Arrears" |
autoRenew | boolean | Quote root | Whether the subscription auto-renews |
renewalTerm | number | Quote root | Term length for renewals (defaults to subscriptionTerm) |
evergreen | boolean | Quote root | Whether the subscription is open-ended with no fixed end date |
Key Behaviors Summary
Scenario | What Happens |
|---|---|
Start + term provided, no end date | End date is calculated automatically |
Start + end date provided, no term | Term is calculated automatically |
All three provided | Start + term used; end date verified |
Product-level term override | Product uses its own dates/term instead of quote header |
autoRenew: true | Subscription renews at end of term for renewalTerm months |
evergreen: true | No end date; subscription continues until canceled |
evergreen: true + autoRenew: true | Conflict -- do not combine; evergreen has no renewal boundary |
Backdated start date | Accepted; pricing calculated normally from the past date |
billingPeriod / billingTiming | Affects invoice scheduling, not the quote total amount |
Next Steps
- DiscountsDiscounts -- Apply header, parent, and line-level discretionary discounts
- Price TagsPrice Tags -- Apply tiered, volume, and ramp pricing adjustments
- BundlesBundles -- Work with bundle products and add-ons
- Create Quote OverviewCreate Quote Overview -- Return to the full API reference