Getting Started with Price Tags
This guide walks you through the essential price tag operations in the Nue Self-Service API. You'll learn how to retrieve price tag information, understand pricing structures, and implement dynamic pricing for your applications.
Prerequisites
Before you begin, ensure you have:
- A valid Nue API key
- Access to the Nue Lifecycle Manager API
- Basic understanding of REST APIs and JSON
- Published price tags in your Nue environment (only published price tags appear in the API)
Authentication
All price tag operations 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");Understanding Price Tags
Price tags are powerful pricing rules that modify base product prices through:
- Volume discounts based on quantity purchased
- Term discounts based on subscription length
- Tiered pricing with different rates at different levels
- Time-limited promotions with start and end dates
Retrieving Price Tag Information
The price tag API allows you to fetch all published price tags or specific tags by ID. To learn more about publishing price tags, please read here.
Fetch All Price Tags
Try it now: Fetch price tags API →
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
const requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
fetch("https://api.nue.io/catalog/price-tags", requestOptions)
.then(response => response.json())
.then(result => {
console.log('Price tags loaded:', result);
// Display each price tag
result.forEach(priceTag => {
console.log(`Price Tag: ${priceTag.name}`);
console.log(`Code: ${priceTag.code}`);
console.log(`Type: ${priceTag.priceTagType}`);
console.log(`Active: ${priceTag.active}`);
console.log(`Tiers: ${priceTag.priceTiers.length}`);
console.log('---');
});
})
.catch(error => console.log('error', error));Fetch Specific Price Tag
Try it now: Fetch price tags API →
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
// Fetch a specific price tag by code
const priceTagCode = "FFT";
const requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
fetch(`https://api.nue.io/catalog/price-tags/${priceTagCode}`, requestOptions)
.then(response => response.json())
.then(result => {
console.log('Price tag details:', result);
const priceTag = result[0]; // API returns array even for single price tag
if (priceTag) {
console.log(`Price Tag Name: ${priceTag.name}`);
console.log(`Code: ${priceTag.code}`);
console.log(`Description: ${priceTag.description}`);
console.log(`Price Type: ${priceTag.priceType}`);
console.log(`Publish Status: ${priceTag.publishStatus}`);
// Display pricing tiers
if (priceTag.priceTiers && priceTag.priceTiers.length > 0) {
console.log('Pricing Tiers:');
priceTag.priceTiers.forEach((tier, index) => {
console.log(` Tier ${index + 1}:`);
console.log(` Range: ${tier.startUnit || 0} - ${tier.endUnit || '∞'}`);
console.log(` Charge Model: ${tier.chargeModel}`);
if (tier.discountPercentage) {
console.log(` Discount: ${tier.discountPercentage}%`);
}
if (tier.amount) {
console.log(` Amount: $${tier.amount}`);
}
});
}
}
})
.catch(error => console.log('error', error));Understanding Price Tag Structure
Price tags in the Nue catalog have a comprehensive data structure. Here's what you'll typically work with:
Core Price Tag Fields
- id: Unique price tag identifier (Salesforce Price Tag ID)
- name: Display name for the price tag
- code: Unique code for API references and promotions (used for fetching individual price tags)
- description: Detailed explanation of the pricing rule
- active: Whether the price tag is currently active
- publishStatus: Whether the price tag is published for self-service (only "Published" price tags appear in API responses)
Pricing Configuration
- priceTagType: "Quantity" or "Term" based pricing
- priceType: "Volume", "Tiered", or "Ramp" pricing model
- uomDimension: Unit of measure (User, License, etc.)
- startTime: When the pricing becomes effective
- endTime: When the pricing expires (optional)
Price Tiers
Each price tag contains priceTiers that define specific pricing rules:
- chargeModel: "PerUnit" or "FlatFee"
- startUnit: Beginning of tier range
- endUnit: End of tier range
- amount: Price amount for price tags
- discountPercentage: Percentage discount for discount tags
Building a Price Tag Display
Here's a practical example of building a price tag display for your application:
async function buildPriceTagCatalog() {
const myHeaders = new Headers();
myHeaders.append("nue-api-key", "YOUR_API_KEY_HERE");
myHeaders.append("Content-Type", "application/json");
try {
const response = await fetch("https://api.nue.io/catalog/price-tags", {
method: 'GET',
headers: myHeaders
});
const priceTags = await response.json();
// Note: Only published price tags are returned by the API
// Filter only active price tags (publishStatus will always be 'Published')
const activePriceTags = priceTags.filter(tag => tag.active);
// Organize price tags by type
const organizedTags = {
volume: [],
term: [],
promotional: []
};
activePriceTags.forEach(tag => {
const tagInfo = {
id: tag.id,
name: tag.name,
code: tag.code,
description: tag.description,
type: tag.priceTagType,
priceType: tag.priceType,
uomDimension: tag.uomDimension,
isTimeLimited: tag.endTime ? true : false,
expiryDate: tag.endTime,
tiers: tag.priceTiers.map(tier => ({
range: `${tier.startUnit || 0} - ${tier.endUnit || '∞'}`,
chargeModel: tier.chargeModel,
discount: tier.discountPercentage || 0,
amount: tier.amount || 0
}))
};
// Categorize by type
if (tag.priceTagType === 'Quantity') {
organizedTags.volume.push(tagInfo);
} else if (tag.priceTagType === 'Term') {
organizedTags.term.push(tagInfo);
}
// Check if it's promotional (time-limited)
if (tag.endTime) {
organizedTags.promotional.push(tagInfo);
}
});
console.log('Price Tag Catalog ready for display:', organizedTags);
return organizedTags;
} catch (error) {
console.error('Failed to load price tag catalog:', error);
throw error;
}
}
// Usage
buildPriceTagCatalog()
.then(catalog => {
// Render your price tag catalog UI
console.log('\n📊 Volume-Based Price Tags:');
catalog.volume.forEach(tag => {
console.log(`🏷️ ${tag.name} (${tag.code})`);
console.log(` ${tag.description}`);
console.log(` Unit: ${tag.uomDimension}`);
tag.tiers.forEach((tier, index) => {
console.log(` Tier ${index + 1}: ${tier.range} units`);
if (tier.discount > 0) {
console.log(` Discount: ${tier.discount}%`);
}
if (tier.amount > 0) {
console.log(` Price: $${tier.amount}`);
}
});
console.log('');
});
console.log('\n📅 Term-Based Price Tags:');
catalog.term.forEach(tag => {
console.log(`🏷️ ${tag.name} (${tag.code})`);
console.log(` ${tag.description}`);
tag.tiers.forEach((tier, index) => {
console.log(` Tier ${index + 1}: ${tier.range}`);
if (tier.discount > 0) {
console.log(` Discount: ${tier.discount}%`);
}
});
console.log('');
});
if (catalog.promotional.length > 0) {
console.log('\n🎉 Promotional Price Tags:');
catalog.promotional.forEach(tag => {
console.log(`🏷️ ${tag.name} (${tag.code})`);
console.log(` ${tag.description}`);
console.log(` Expires: ${tag.expiryDate}`);
console.log('');
});
}
});Filtering and Searching Price Tags
For better user experience, you'll want to implement filtering and search:
function filterPriceTags(priceTags, filters = {}) {
return priceTags.filter(tag => {
// Filter by active status
if (filters.activeOnly && !tag.active) return false;
// Note: publishStatus will always be 'Published' since only published tags are returned
// No need to filter by publication status
// Filter by price tag type
if (filters.type && tag.priceTagType !== filters.type) return false;
// Filter by code search
if (filters.code) {
const searchTerm = filters.code.toLowerCase();
if (!tag.code.toLowerCase().includes(searchTerm)) return false;
}
// Filter by name/description search
if (filters.search) {
const searchTerm = filters.search.toLowerCase();
const matchesName = tag.name.toLowerCase().includes(searchTerm);
const matchesDescription = tag.description?.toLowerCase().includes(searchTerm);
if (!matchesName && !matchesDescription) return false;
}
// Filter by time validity
if (filters.validNow) {
const now = new Date();
const startTime = tag.startTime ? new Date(tag.startTime) : new Date('1970-01-01');
const endTime = tag.endTime ? new Date(tag.endTime) : new Date('2099-12-31');
if (now < startTime || now > endTime) return false;
}
return true;
});
}
// Usage example
async function searchPriceTags() {
const allTags = await buildPriceTagCatalog();
const flatTags = [...allTags.volume, ...allTags.term, ...allTags.promotional];
// Search for volume discounts currently valid
const volumeDiscounts = filterPriceTags(flatTags, {
type: 'Quantity',
validNow: true,
activeOnly: true
});
console.log(`Found ${volumeDiscounts.length} active volume discounts`);
// Search for price tags by code
const specificTag = filterPriceTags(flatTags, {
code: 'ENTERPRISE'
});
console.log(`Found ${specificTag.length} tags matching 'ENTERPRISE'`);
}Calculating Price Impact
Understanding how price tags affect final pricing is crucial for building quotes:
function calculatePriceImpact(basePrice, quantity, priceTag) {
if (!priceTag || !priceTag.tiers || priceTag.tiers.length === 0) {
return {
originalPrice: basePrice * quantity,
finalPrice: basePrice * quantity,
savings: 0,
effectiveTier: null
};
}
// Find applicable tier based on quantity
let applicableTier = null;
for (const tier of priceTag.tiers) {
const tierStart = tier.startUnit || 0;
const tierEnd = tier.endUnit || Infinity;
if (quantity >= tierStart && quantity <= tierEnd) {
applicableTier = tier;
break;
}
}
if (!applicableTier) {
return {
originalPrice: basePrice * quantity,
finalPrice: basePrice * quantity,
savings: 0,
effectiveTier: null
};
}
let finalPrice;
const originalPrice = basePrice * quantity;
if (priceTag.priceType === 'Volume') {
// Volume pricing: all units get the same rate
if (applicableTier.discountPercentage) {
const discountMultiplier = 1 - (applicableTier.discountPercentage / 100);
finalPrice = originalPrice * discountMultiplier;
} else if (applicableTier.amount) {
finalPrice = applicableTier.amount * quantity;
} else {
finalPrice = originalPrice;
}
} else if (priceTag.priceType === 'Tiered') {
// Tiered pricing: different rates for different portions
finalPrice = 0;
let remainingQuantity = quantity;
for (const tier of priceTag.tiers.sort((a, b) => a.startUnit - b.startUnit)) {
const tierStart = tier.startUnit || 0;
const tierEnd = tier.endUnit || Infinity;
if (remainingQuantity <= 0) break;
const tierQuantity = Math.min(remainingQuantity, tierEnd - tierStart);
if (tier.discountPercentage) {
const discountMultiplier = 1 - (tier.discountPercentage / 100);
finalPrice += (basePrice * tierQuantity * discountMultiplier);
} else if (tier.amount) {
finalPrice += (tier.amount * tierQuantity);
} else {
finalPrice += (basePrice * tierQuantity);
}
remainingQuantity -= tierQuantity;
}
}
return {
originalPrice: originalPrice,
finalPrice: finalPrice,
savings: originalPrice - finalPrice,
savingsPercentage: ((originalPrice - finalPrice) / originalPrice) * 100,
effectiveTier: applicableTier
};
}
// Usage example
async function demonstratePricing() {
const priceTags = await buildPriceTagCatalog();
const volumeTag = priceTags.volume[0]; // Get first volume discount
if (volumeTag) {
const scenarios = [
{ quantity: 5, basePrice: 100 },
{ quantity: 25, basePrice: 100 },
{ quantity: 100, basePrice: 100 }
];
console.log(`\n💰 Pricing with ${volumeTag.name}:`);
scenarios.forEach(scenario => {
const pricing = calculatePriceImpact(scenario.basePrice, scenario.quantity, volumeTag);
console.log(`\n📊 ${scenario.quantity} units at $${scenario.basePrice} base price:`);
console.log(` Original: $${pricing.originalPrice.toFixed(2)}`);
console.log(` Final: $${pricing.finalPrice.toFixed(2)}`);
console.log(` Savings: $${pricing.savings.toFixed(2)} (${pricing.savingsPercentage.toFixed(1)}%)`);
if (pricing.effectiveTier) {
console.log(` Applied Tier: ${pricing.effectiveTier.range}`);
}
});
}
}
// Run the demonstration
demonstratePricing();Common Patterns and Best Practices
1. Error Handling
Always implement proper error handling for your price tag operations:
async function safePriceTagFetch(priceTagCode = null) {
try {
const url = priceTagCode
? `https://api.nue.io/catalog/price-tags/${priceTagCode}`
: 'https://api.nue.io/catalog/price-tags';
const response = await fetch(url, {
method: 'GET',
headers: myHeaders
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const priceTags = await response.json();
if (priceTagCode && priceTags.length === 0) {
throw new Error(`Price tag with code ${priceTagCode} not found or not published`);
}
return priceTags;
} catch (error) {
console.error('Price tag fetch error:', error);
// Return empty array for graceful degradation
return [];
}
}2. Caching Price Tags
Price tags don't change frequently, so implement caching:
class PriceTagCache {
constructor(ttlMinutes = 60) {
this.cache = new Map();
this.ttl = ttlMinutes * 60 * 1000; // Convert to milliseconds
}
set(key, data) {
this.cache.set(key, {
data,
timestamp: Date.now()
});
}
get(key) {
const cached = this.cache.get(key);
if (!cached) return null;
// Check if cache has expired
if (Date.now() - cached.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return cached.data;
}
async getPriceTags() {
const cached = this.get('all-price-tags');
if (cached) {
console.log('Using cached price tag data');
return cached;
}
console.log('Fetching fresh price tag data');
const priceTags = await safePriceTagFetch();
this.set('all-price-tags', priceTags);
return priceTags;
}
}
// Usage
const priceTagCache = new PriceTagCache(60); // 60-minute cache
const priceTags = await priceTagCache.getPriceTags();3. Price Tag Validation
Validate price tags before applying them:
function validatePriceTag(priceTag) {
const now = new Date();
// Check if active
if (!priceTag.active) {
return { valid: false, reason: 'Price tag is not active' };
}
// Note: publishStatus will always be 'Published' since only published tags are returned by the API
// No need to check publication status
// Check time validity
if (priceTag.startTime && new Date(priceTag.startTime) > now) {
return { valid: false, reason: 'Price tag has not started yet' };
}
if (priceTag.endTime && new Date(priceTag.endTime) < now) {
return { valid: false, reason: 'Price tag has expired' };
}
return { valid: true, reason: 'Price tag is valid' };
}Next Steps
Now that you understand basic price tag operations, you can:
- Learn about pricing strategies in the Key Considerations guide
- Understand price tag types for implementing specific pricing models
- Explore the data model to understand all available fields
- Build dynamic pricing with real-time price calculations
Move on to Key Considerations for Price Tags to learn about pricing strategies and implementation best practices, or Price Tag Types to understand different pricing models you can implement.