Multi-Currency
Multi-Currency
The Nue CPQ Quote API supports creating quotes in different currencies when your org has multi-currency enabled. Set the currencyIsoCode field at the quote level to control which currency the pricing engine uses for PBE resolution and amount calculations.
Prerequisites
Before using multi-currency quotes, ensure the following:
- Multi-currency is enabled in your Nue org
- Price Book Entries (PBEs) exist for the target currency -- each product must have a PBE in the requested currency
- Currency ISO codes follow the ISO 4217 standard (e.g., USD, EUR, GBP, JPY)
If a product does not have a Price Book Entry for the requested currency, the API returns an error.
Setting the Currency
Include currencyIsoCode as a top-level field in the request body:
{
"opportunityId": "006xx000001abc123",
"name": "EUR Quote",
"currencyIsoCode": "EUR",
"products": [...]
}The pricing engine resolves PBEs in the specified currency and calculates all amounts in that currency.
PBE Currency Matching
Request Currency | PBE Currency | Result |
|---|---|---|
"EUR" | EUR PBE exists | EUR PBE is used; amounts in EUR |
"EUR" | No EUR PBE | Error: PRICEBOOK_ENTRY_MISMATCH |
(omitted) | Default currency PBE exists | Default org currency is used |
(omitted) | No default PBE | Error: PRICEBOOK_ENTRY_MISMATCH |
Authentication
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");Use Case 1: EUR Standalone Product
Create a preview quote for a standalone product priced in Euros.
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
const quoteData = {
opportunityId: "006xx000001abc123",
name: "EU Enterprise License",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
currencyIsoCode: "EUR",
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(`Currency: ${result.quote.currencyIsoCode}`); // "EUR"
console.log(`Total Amount: ${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": "EU Enterprise License",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"currencyIsoCode": "EUR",
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
]
}'The pricing engine resolves the EUR Price Book Entry for NUE_ON_SALESFORCE and returns all amounts in Euros.
Use Case 2: USD Baseline Comparison
Create the same quote in USD for side-by-side comparison with the EUR quote.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "US Enterprise License",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
currencyIsoCode: "USD",
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(`Currency: ${result.quote.currencyIsoCode}`); // "USD"
console.log(`Total Amount: $${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": "US Enterprise License",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"currencyIsoCode": "USD",
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
]
}'The USD and EUR quotes use different PBEs with potentially different list prices. Compare totalAmount values across both responses.
Use Case 3: No PBE for Requested Currency (Error)
If you request a currency for which no Price Book Entry exists, the API returns an error.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "JPY Quote -- No PBE",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
currencyIsoCode: "JPY",
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 => {
if (result.status === 400) {
console.log('Error:', result.message);
// "No Price Book Entry found for product NUE_ON_SALESFORCE with currency JPY"
}
})
.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": "JPY Quote -- No PBE",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"currencyIsoCode": "JPY",
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
]
}'Expected error response:
{
"status": 400,
"error": "Failed to create quote",
"message": "No Price Book Entry found for product NUE_ON_SALESFORCE with currency JPY"
}Use Case 4: EUR Bundles
Multi-currency works with bundles. All products in the bundle -- parent and add-ons -- must have PBEs in the target currency.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "EUR Bundle Quote",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
currencyIsoCode: "EUR",
products: [
{
productSku: "ENTERPRISE_BUNDLE",
uom: "License/Month",
quantity: 20,
addOns: [
{ productSku: "ADDON_SUPPORT", uom: "License/Month", quantity: 1 },
{ productSku: "ADDON_STORAGE", uom: "GB/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(`Currency: ${result.quote.currencyIsoCode}`); // "EUR"
console.log(`Bundle total: ${result.quote.totalAmount}`);
const parent = result.quoteLineItems[0];
console.log(`Parent: ${parent.totalPrice}`);
parent.childrenLineItems.forEach(child => {
console.log(` ${child.product.sku}: ${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": "EUR Bundle Quote",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"currencyIsoCode": "EUR",
"products": [
{
"productSku": "ENTERPRISE_BUNDLE",
"uom": "License/Month",
"quantity": 20,
"addOns": [
{ "productSku": "ADDON_SUPPORT", "uom": "License/Month", "quantity": 1 },
{ "productSku": "ADDON_STORAGE", "uom": "GB/Month", "quantity": 100 }
]
}
]
}'If any add-on is missing an EUR PBE, the entire quote request fails with a PRICEBOOK_ENTRY_MISMATCH error.
Use Case 5: EUR with Discounts
Discounts work identically regardless of currency. The discount percentage is applied to the currency-specific list price.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "EUR with Discount",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
currencyIsoCode: "EUR",
discount: 10,
products: [
{ productSku: "NUE_ON_SALESFORCE", uom: "User/Month", quantity: 10, discount: 15 }
]
};
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(`List price (EUR): ${line.listTotalPrice}`);
console.log(`Discount: ${line.discount}%`); // 15% (line-level overrides header)
console.log(`Total price (EUR): ${line.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": "EUR with Discount",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"currencyIsoCode": "EUR",
"discount": 10,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10, "discount": 15 }
]
}'The line-level 15% discount overrides the header-level 10% discount, applied to the EUR list price.
Use Case 6: EUR with Quantity Scaling
Quantity scaling works the same across currencies. The pricing formula listPrice x quantity x term uses the currency-specific list price.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "EUR Quantity Scaling",
subscriptionStartDate: "2026-01-01",
subscriptionEndDate: "2027-01-01",
subscriptionTermDimension: "Month",
subscriptionTerm: 12,
currencyIsoCode: "EUR",
products: [
{ productSku: "NUE_ON_SALESFORCE", 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 => {
const line = result.quoteLineItems[0];
console.log(`Unit price (EUR): ${line.listUnitPrice}`);
console.log(`Quantity: ${line.quantity}`); // 5
console.log(`Term: 12 months`);
console.log(`List total: ${line.listTotalPrice}`); // unitPrice * 5 * 12
console.log(`Total: ${line.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": "EUR Quantity Scaling",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"currencyIsoCode": "EUR",
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 5 }
]
}'The listTotalPrice is calculated as EUR listUnitPrice x 5 x 12.
Use Case 7: Missing currencyIsoCode in Multi-Currency Org
When currencyIsoCode is omitted in a multi-currency org, the pricing engine falls back to the org's default currency.
const quoteData = {
opportunityId: "006xx000001abc123",
name: "Default Currency Fallback",
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(`Currency: ${result.quote.currencyIsoCode}`); // Org's default (e.g., "USD")
console.log(`Total Amount: ${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": "Default Currency Fallback",
"subscriptionStartDate": "2026-01-01",
"subscriptionEndDate": "2027-01-01",
"subscriptionTermDimension": "Month",
"subscriptionTerm": 12,
"products": [
{ "productSku": "NUE_ON_SALESFORCE", "uom": "User/Month", "quantity": 10 }
]
}'The response's currencyIsoCode reflects the org's default currency. PBE resolution uses that default currency.
Multi-Currency Behavior Summary
Behavior | Description |
|---|---|
Currency field | Set currencyIsoCode at the quote level (top-level property) |
PBE resolution | Engine resolves PBEs matching the requested currency |
All-or-nothing | Every product in the quote must have a PBE in the target currency |
Discount behavior | Percentage discounts work identically across currencies |
Amount discounts | Fixed discountAmount values are in the specified currency |
Default fallback | If currencyIsoCode is omitted, the org's default currency is used |
Bundle support | All bundle components must have PBEs in the target currency |
Troubleshooting
Symptom | Likely Cause | Resolution |
|---|---|---|
PRICEBOOK_ENTRY_MISMATCH error | No PBE exists for the requested currency | Create PBEs in the target currency for all products |
Partial bundle failure | One add-on missing a currency PBE | Ensure all bundle components have PBEs in the target currency |
Unexpected currency in response | currencyIsoCode not set in request | Explicitly set currencyIsoCode in the request body |
Wrong amounts | PBE list price not set for currency | Verify the list price on the currency-specific PBE |