Tiered Pricing Models
Scale pricing based on volume with tier-based discounting strategies
Tiered pricing adjusts rates based on consumption volume, rewarding high-volume customers with better pricing while maximizing revenue from all segments. This model incentivizes growth and provides predictable scaling economics.
When to Use Tiered Pricing
Best for:
- Services with low marginal costs
- High-volume usage patterns
- Customer growth incentives
- Market segmentation strategies
- Scale economies you can pass on
Not ideal for:
- High fixed costs per unit
- Minimal volume variation
- Complex value propositions
- Services with flat cost structures
Core Patterns
Pattern 1: Volume-Based Tiers
Charge different rates based on total usage volume:
import $, { db, on, send } from 'sdk.do'
const dataProcessingService = await $.Service.create({
name: 'Data Processing Pipeline',
type: $.ServiceType.DataProcessing,
pricing: {
model: 'volume-tiered',
unit: 'gigabyte',
tiers: [
{
name: 'tier-1',
min: 0,
max: 100,
rate: 0.1, // $0.10/GB for first 100 GB
},
{
name: 'tier-2',
min: 100,
max: 1000,
rate: 0.08, // $0.08/GB for 100-1,000 GB
},
{
name: 'tier-3',
min: 1000,
max: 10000,
rate: 0.06, // $0.06/GB for 1,000-10,000 GB
},
{
name: 'tier-4',
min: 10000,
max: Infinity,
rate: 0.04, // $0.04/GB for 10,000+ GB
},
],
},
})
// Calculate tiered pricing
function calculateTieredPrice(
volume: number,
tiers: any[]
): {
total: number
breakdown: Array<{ tier: string; volume: number; rate: number; cost: number }>
} {
let remainingVolume = volume
let total = 0
const breakdown = []
for (const tier of tiers) {
if (remainingVolume <= 0) break
// Calculate volume in this tier
const tierMax = tier.max === Infinity ? Infinity : tier.max - tier.min
const volumeInTier = Math.min(remainingVolume, tierMax)
// Calculate cost for this tier
const cost = volumeInTier * tier.rate
total += cost
breakdown.push({
tier: tier.name,
volume: volumeInTier,
rate: tier.rate,
cost,
})
remainingVolume -= volumeInTier
}
return { total, breakdown }
}
on($.ServiceRequest.created, async (request) => {
if (request.serviceId !== dataProcessingService.id) return
try {
// Process data
const result = await processData(request.inputs.data)
const volumeGB = result.processedBytes / 1024 ** 3
// Calculate tiered pricing
const pricing = calculateTieredPrice(volumeGB, dataProcessingService.pricing.tiers)
// Deliver result
await send($.ServiceResult.deliver, {
requestId: request.id,
outputs: {
processedData: result.data,
statistics: result.stats,
volumeProcessed: volumeGB,
},
})
// Charge customer
await send($.Payment.charge, {
customerId: request.customerId,
amount: pricing.total,
description: `Data Processing - ${volumeGB.toFixed(2)} GB`,
breakdown: {
volume: volumeGB,
tiers: pricing.breakdown,
total: pricing.total,
averageRate: pricing.total / volumeGB,
},
})
} catch (error) {
await send($.ServiceRequest.fail, {
requestId: request.id,
error: error.message,
})
}
})
async function processData(data: any) {
// Simulate data processing
const processedBytes = Buffer.byteLength(JSON.stringify(data))
return {
data: { processed: true },
stats: { bytes: processedBytes },
processedBytes,
}
}Example Pricing:
- 50 GB = $5.00 (50 × $0.10)
- 500 GB = $42.00 (100 × $0.10 + 400 × $0.08)
- 5,000 GB = $370.00 (100 × $0.10 + 900 × $0.08 + 4,000 × $0.06)
- 50,000 GB = $2,770.00 (full tier progression + 40,000 × $0.04)
Savings Illustration:
- 50 GB at flat $0.10 rate = $5.00 (no savings)
- 5,000 GB at tiered rates = $370.00 vs $500.00 flat = 26% savings
- 50,000 GB at tiered rates = $2,770.00 vs $5,000.00 flat = 45% savings
Pattern 2: All-Units Tiering
Apply the tier rate to all units once a threshold is reached:
const transcriptionService = await $.Service.create({
name: 'Audio Transcription Service',
type: $.ServiceType.Transcription,
pricing: {
model: 'all-units-tiered',
unit: 'minute',
tiers: [
{
name: 'standard',
threshold: 0,
rate: 0.05, // $0.05/minute for 0-999 minutes
},
{
name: 'volume',
threshold: 1000,
rate: 0.04, // $0.04/minute for 1,000-9,999 minutes
},
{
name: 'enterprise',
threshold: 10000,
rate: 0.03, // $0.03/minute for 10,000+ minutes
},
],
},
})
// All-units calculation: once you reach a tier, all units use that rate
function calculateAllUnitsTieredPrice(
volume: number,
tiers: any[]
): {
total: number
tier: string
rate: number
savings: number
} {
// Find applicable tier (highest threshold not exceeding volume)
let applicableTier = tiers[0]
for (const tier of tiers) {
if (volume >= tier.threshold) {
applicableTier = tier
}
}
const total = volume * applicableTier.rate
const standardRate = tiers[0].rate
const savings = volume * standardRate - total
return {
total,
tier: applicableTier.name,
rate: applicableTier.rate,
savings,
}
}
on($.ServiceRequest.created, async (request) => {
if (request.serviceId !== transcriptionService.id) return
try {
// Transcribe audio
const transcription = await transcribeAudio(request.inputs.audioUrl)
const minutes = Math.ceil(transcription.duration / 60)
// Calculate pricing using all-units model
const pricing = calculateAllUnitsTieredPrice(minutes, transcriptionService.pricing.tiers)
// Deliver result
await send($.ServiceResult.deliver, {
requestId: request.id,
outputs: {
transcript: transcription.text,
duration: transcription.duration,
confidence: transcription.confidence,
words: transcription.words,
},
})
// Charge customer
await send($.Payment.charge, {
customerId: request.customerId,
amount: pricing.total,
description: `Audio Transcription - ${minutes} minutes`,
breakdown: {
minutes,
tier: pricing.tier,
rate: pricing.rate,
total: pricing.total,
savings: pricing.savings,
},
})
} catch (error) {
await send($.ServiceRequest.fail, {
requestId: request.id,
error: error.message,
})
}
})
async function transcribeAudio(audioUrl: string) {
// Simulate transcription
return {
text: 'Transcribed text...',
duration: 120, // seconds
confidence: 0.95,
words: 250,
}
}Example Pricing (All-Units Model):
- 500 minutes = $25.00 (500 × $0.05)
- 1,500 minutes = $60.00 (1,500 × $0.04) - saves $15 vs standard
- 15,000 minutes = $450.00 (15,000 × $0.03) - saves $300 vs standard
Key Difference: In all-units tiering, crossing a threshold retroactively applies the better rate to ALL units, not just those above the threshold.
Pattern 3: Monthly Accumulated Tiers
Track monthly usage and apply tiers progressively:
const apiService = await $.Service.create({
name: 'RESTful API Platform',
type: $.ServiceType.API,
pricing: {
model: 'monthly-accumulated-tiered',
unit: 'request',
resetPeriod: 'month',
tiers: [
{
name: 'free',
min: 0,
max: 10000,
rate: 0, // First 10k requests free
},
{
name: 'starter',
min: 10000,
max: 100000,
rate: 0.0001, // $0.0001 per request for 10k-100k
},
{
name: 'growth',
min: 100000,
max: 1000000,
rate: 0.00008, // $0.00008 per request for 100k-1M
},
{
name: 'scale',
min: 1000000,
max: Infinity,
rate: 0.00005, // $0.00005 per request for 1M+
},
],
},
})
// Track monthly usage
on($.APIRequest.completed, async (apiRequest) => {
// Record usage
await db.create($.UsageRecord, {
customerId: apiRequest.customerId,
serviceId: apiService.id,
timestamp: new Date(),
units: 1,
metadata: {
endpoint: apiRequest.endpoint,
method: apiRequest.method,
statusCode: apiRequest.statusCode,
},
})
})
// Monthly billing
on($.BillingCycle.ended, async (cycle) => {
const customers = await db.query($.Customer, { status: 'active' })
for (const customer of customers) {
// Get monthly usage
const usage = await db.query($.UsageRecord, {
where: {
customerId: customer.id,
serviceId: apiService.id,
timestamp: { gte: cycle.start, lte: cycle.end },
},
})
const totalRequests = usage.length
// Calculate tiered pricing
const pricing = calculateTieredPrice(totalRequests, apiService.pricing.tiers)
if (pricing.total > 0) {
// Create invoice
await send($.Invoice.create, {
customerId: customer.id,
period: { start: cycle.start, end: cycle.end },
lineItems: pricing.breakdown.map((tier) => ({
description: `API Requests (${tier.tier}) - ${tier.volume.toLocaleString()} requests`,
quantity: tier.volume,
rate: tier.rate,
amount: tier.cost,
})),
total: pricing.total,
})
}
}
})Example Monthly Billing:
- Month 1: 50,000 requests = $4.00 (first 10k free + 40k × $0.0001)
- Month 2: 500,000 requests = $45.00 (10k free + 90k × $0.0001 + 400k × $0.00008)
- Month 3: 2,000,000 requests = $129.00 (full tier progression)
Pattern 4: Commit-Based Tiers
Customers commit to volume for better rates:
const cloudStorageService = await $.Service.create({
name: 'Cloud Storage Platform',
type: $.ServiceType.Storage,
pricing: {
model: 'commit-tiered',
unit: 'terabyte-month',
payAsYouGo: {
rate: 0.15, // $0.15/TB-month without commitment
},
commitments: [
{
name: 'starter-commit',
monthlyCommit: 10, // 10 TB minimum
rate: 0.12, // $0.12/TB-month (20% discount)
term: 12, // 12-month contract
overage: 0.13, // $0.13/TB over commitment
},
{
name: 'growth-commit',
monthlyCommit: 100, // 100 TB minimum
rate: 0.1, // $0.10/TB-month (33% discount)
term: 12,
overage: 0.11,
},
{
name: 'enterprise-commit',
monthlyCommit: 1000, // 1 PB minimum
rate: 0.08, // $0.08/TB-month (47% discount)
term: 12,
overage: 0.09,
},
],
},
})
on($.StorageCommitment.create, async (commitmentRequest) => {
const commitment = cloudStorageService.pricing.commitments.find((c) => c.name === commitmentRequest.tier)
if (!commitment) {
throw new Error('Invalid commitment tier')
}
// Create commitment contract
const contract = await db.create($.Commitment, {
customerId: commitmentRequest.customerId,
serviceId: cloudStorageService.id,
tier: commitment.name,
monthlyCommit: commitment.monthlyCommit,
rate: commitment.rate,
overageRate: commitment.overage,
term: commitment.term,
startDate: new Date(),
endDate: addMonths(new Date(), commitment.term),
status: 'active',
})
// Charge first month
await send($.Payment.charge, {
customerId: commitmentRequest.customerId,
amount: commitment.monthlyCommit * commitment.rate,
description: `Storage Commitment - ${commitment.monthlyCommit} TB`,
contractId: contract.id,
})
return contract
})
// Monthly billing with commitment
on($.BillingCycle.ended, async (cycle) => {
const commitments = await db.query($.Commitment, {
where: {
serviceId: cloudStorageService.id,
status: 'active',
endDate: { gte: cycle.end },
},
})
for (const commitment of commitments) {
// Get actual usage
const usage = await getMonthlyStorageUsage(commitment.customerId, cycle.start, cycle.end)
const averageTB = usage.averageTerabytes
// Calculate charges
const baseCharge = commitment.monthlyCommit * commitment.rate
let overageCharge = 0
if (averageTB > commitment.monthlyCommit) {
const overage = averageTB - commitment.monthlyCommit
overageCharge = overage * commitment.overageRate
}
const total = baseCharge + overageCharge
// Create invoice
const lineItems = [
{
description: `Storage Commitment - ${commitment.monthlyCommit} TB`,
quantity: commitment.monthlyCommit,
rate: commitment.rate,
amount: baseCharge,
},
]
if (overageCharge > 0) {
lineItems.push({
description: `Storage Overage - ${(averageTB - commitment.monthlyCommit).toFixed(2)} TB`,
quantity: averageTB - commitment.monthlyCommit,
rate: commitment.overageRate,
amount: overageCharge,
})
}
await send($.Invoice.create, {
customerId: commitment.customerId,
period: { start: cycle.start, end: cycle.end },
lineItems,
total,
metadata: {
actualUsage: averageTB,
commitment: commitment.monthlyCommit,
utilizationRate: (averageTB / commitment.monthlyCommit) * 100,
},
})
// Alert if underutilized
if (averageTB < commitment.monthlyCommit * 0.7) {
await send($.Customer.notify, {
customerId: commitment.customerId,
type: 'commitment-underutilized',
message: `Your storage usage is only ${Math.round((averageTB / commitment.monthlyCommit) * 100)}% of your commitment`,
recommendation: 'Consider downgrading your commitment to save money',
})
}
}
})
async function getMonthlyStorageUsage(customerId: string, start: Date, end: Date) {
// Calculate average storage used during the period
const samples = await db.query($.StorageSample, {
where: {
customerId,
timestamp: { gte: start, lte: end },
},
})
const averageBytes = samples.reduce((sum, s) => sum + s.bytes, 0) / samples.length
const averageTerabytes = averageBytes / 1024 ** 4
return { averageTerabytes }
}
function addMonths(date: Date, months: number): Date {
const result = new Date(date)
result.setMonth(result.getMonth() + months)
return result
}Commitment Pricing:
- Pay-as-you-go: $0.15/TB-month
- 10 TB commitment: $0.12/TB-month (save $360/year)
- 100 TB commitment: $0.10/TB-month (save $6,000/year)
- 1 PB commitment: $0.08/TB-month (save $84,000/year)
Example Billing:
- Customer with 100 TB commitment uses 120 TB:
- Base: 100 TB × $0.10 = $10.00
- Overage: 20 TB × $0.11 = $2.20
- Total: $12.20
Pattern 5: Dynamic Tier Promotion
Automatically promote customers to better tiers:
const emailDeliveryService = await $.Service.create({
name: 'Transactional Email Service',
type: $.ServiceType.Email,
pricing: {
model: 'dynamic-tiered',
unit: 'email',
evaluationPeriod: 'rolling-30-days',
tiers: [
{
name: 'starter',
threshold: 0,
rate: 0.001, // $0.001 per email
features: ['basic-analytics', 'email-support'],
},
{
name: 'professional',
threshold: 50000, // Auto-promote at 50k emails/month
rate: 0.0008, // $0.0008 per email (20% discount)
features: ['advanced-analytics', 'priority-support', 'custom-domains'],
},
{
name: 'enterprise',
threshold: 500000, // Auto-promote at 500k emails/month
rate: 0.0005, // $0.0005 per email (50% discount)
features: ['all-features', 'dedicated-ip', 'phone-support', 'sla-guarantee'],
},
],
},
})
// Track rolling 30-day usage
async function getRolling30DayVolume(customerId: string): Promise<number> {
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
const usage = await db.query($.UsageRecord, {
where: {
customerId,
serviceId: emailDeliveryService.id,
timestamp: { gte: thirtyDaysAgo },
},
})
return usage.reduce((sum, record) => sum + record.units, 0)
}
// Determine applicable tier
async function determineCustomerTier(customerId: string): Promise<any> {
const rolling30DayVolume = await getRolling30DayVolume(customerId)
let applicableTier = emailDeliveryService.pricing.tiers[0]
for (const tier of emailDeliveryService.pricing.tiers) {
if (rolling30DayVolume >= tier.threshold) {
applicableTier = tier
}
}
return applicableTier
}
on($.ServiceRequest.created, async (request) => {
if (request.serviceId !== emailDeliveryService.id) return
try {
// Send email
const result = await sendTransactionalEmail(request.inputs)
// Determine current tier
const tier = await determineCustomerTier(request.customerId)
// Record usage
await db.create($.UsageRecord, {
customerId: request.customerId,
serviceId: emailDeliveryService.id,
timestamp: new Date(),
units: 1,
rate: tier.rate,
cost: tier.rate,
tier: tier.name,
})
// Check for tier promotion
const rolling30Day = await getRolling30DayVolume(request.customerId)
const nextTier = emailDeliveryService.pricing.tiers.find((t) => t.threshold > rolling30Day && rolling30Day >= t.threshold * 0.9)
let upgradeNotice
if (nextTier) {
upgradeNotice = {
message: `You're close to ${nextTier.name} tier! Send ${Math.ceil(nextTier.threshold - rolling30Day)} more emails to unlock ${(((tier.rate - nextTier.rate) / tier.rate) * 100).toFixed(0)}% discount`,
currentTier: tier.name,
nextTier: nextTier.name,
emailsToUpgrade: nextTier.threshold - rolling30Day,
potentialSavings: (tier.rate - nextTier.rate) * rolling30Day,
}
}
// Deliver result
await send($.ServiceResult.deliver, {
requestId: request.id,
outputs: {
messageId: result.messageId,
status: result.status,
},
pricing: {
tier: tier.name,
rate: tier.rate,
rolling30DayVolume: rolling30Day,
upgradeNotice,
},
})
} catch (error) {
await send($.ServiceRequest.fail, {
requestId: request.id,
error: error.message,
})
}
})
// Daily tier evaluation and notification
on($.DailyJob.run, async () => {
const customers = await db.query($.Customer, { status: 'active' })
for (const customer of customers) {
const currentTier = await determineCustomerTier(customer.id)
const previousTier = await db.findOne($.CustomerTier, {
customerId: customer.id,
serviceId: emailDeliveryService.id,
})
// Check for tier change
if (!previousTier || previousTier.tierName !== currentTier.name) {
// Update tier
await db.upsert($.CustomerTier, {
where: { customerId: customer.id, serviceId: emailDeliveryService.id },
create: {
customerId: customer.id,
serviceId: emailDeliveryService.id,
tierName: currentTier.name,
tierRate: currentTier.rate,
promotedAt: new Date(),
},
update: {
tierName: currentTier.name,
tierRate: currentTier.rate,
promotedAt: new Date(),
},
})
// Send promotion notification
if (previousTier && currentTier.threshold > emailDeliveryService.pricing.tiers.find((t) => t.name === previousTier.tierName)?.threshold) {
await send($.Email.send, {
to: customer.email,
template: 'tier-promotion',
data: {
oldTier: previousTier.tierName,
newTier: currentTier.name,
newRate: currentTier.rate,
discount: (((previousTier.tierRate - currentTier.rate) / previousTier.tierRate) * 100).toFixed(0),
newFeatures: currentTier.features,
},
})
}
}
}
})
async function sendTransactionalEmail(inputs: any) {
// Simulate email sending
return {
messageId: `msg_${Date.now()}`,
status: 'sent',
}
}Dynamic Tier Behavior:
- Continuous evaluation of rolling 30-day usage
- Automatic promotion when thresholds are reached
- Immediate rate adjustment on next request
- Proactive notification when approaching next tier
Example Progression:
- Day 1-20: 30,000 emails at $0.001 = $30.00
- Day 21: Crosses 50k threshold → auto-promoted to Professional
- Day 21-30: 25,000 emails at $0.0008 = $20.00
- Month total: 55,000 emails, cost = $50.00 (vs $55.00 at flat rate)
Pattern 6: Package Tiers with Included Units
Combine base fees with included usage:
const videoTranscodingService = await $.Service.create({
name: 'Video Transcoding Platform',
type: $.ServiceType.VideoProcessing,
pricing: {
model: 'package-tiered',
packages: [
{
name: 'hobby',
monthlyFee: 0,
included: {
minutes: 60, // 1 hour free per month
},
overage: {
rate: 0.05, // $0.05 per minute over
},
limits: {
maxResolution: '1080p',
formats: ['mp4'],
},
},
{
name: 'creator',
monthlyFee: 29,
included: {
minutes: 1000, // ~16 hours included
},
overage: {
rate: 0.03, // $0.03 per minute over
},
limits: {
maxResolution: '4k',
formats: ['mp4', 'webm', 'mov'],
features: ['thumbnails', 'previews'],
},
},
{
name: 'professional',
monthlyFee: 99,
included: {
minutes: 5000, // ~83 hours included
},
overage: {
rate: 0.02, // $0.02 per minute over
},
limits: {
maxResolution: '8k',
formats: ['all'],
features: ['all', 'priority-queue', 'api-access'],
},
},
{
name: 'studio',
monthlyFee: 499,
included: {
minutes: 30000, // 500 hours included
},
overage: {
rate: 0.01, // $0.01 per minute over
},
limits: {
maxResolution: '8k',
formats: ['all'],
features: ['all', 'dedicated-resources', 'sla', 'phone-support'],
},
},
],
},
})
on($.VideoTranscode.request, async (request) => {
// Get customer's package
const subscription = await db.findOne($.Subscription, {
customerId: request.customerId,
serviceId: videoTranscodingService.id,
status: 'active',
})
const pkg = subscription
? videoTranscodingService.pricing.packages.find((p) => p.name === subscription.packageName)
: videoTranscodingService.pricing.packages[0] // Default to hobby
try {
// Get monthly usage
const monthStart = new Date()
monthStart.setDate(1)
monthStart.setHours(0, 0, 0, 0)
const monthlyUsage = await db.query($.UsageRecord, {
where: {
customerId: request.customerId,
serviceId: videoTranscodingService.id,
timestamp: { gte: monthStart },
},
})
const usedMinutes = monthlyUsage.reduce((sum, u) => sum + u.units, 0)
// Check resolution limit
if (request.inputs.resolution > pkg.limits.maxResolution) {
return await send($.ServiceRequest.reject, {
requestId: request.id,
reason: `Resolution ${request.inputs.resolution} exceeds ${pkg.name} package limit (${pkg.limits.maxResolution})`,
upgrade: {
requiredPackage: videoTranscodingService.pricing.packages.find((p) => p.limits.maxResolution >= request.inputs.resolution)?.name,
},
})
}
// Transcode video
const result = await transcodeVideo(request.inputs)
const minutes = Math.ceil(result.duration / 60)
// Calculate cost
let cost = 0
const breakdown: any = {
package: pkg.name,
monthlyFee: pkg.monthlyFee,
includedMinutes: pkg.included.minutes,
usedMinutes: usedMinutes + minutes,
}
// Calculate overage if applicable
if (usedMinutes + minutes > pkg.included.minutes) {
const overageMinutes = Math.max(0, usedMinutes + minutes - pkg.included.minutes)
cost = overageMinutes * pkg.overage.rate
breakdown.overageMinutes = overageMinutes
breakdown.overageRate = pkg.overage.rate
breakdown.overageCost = cost
} else {
breakdown.remainingMinutes = pkg.included.minutes - (usedMinutes + minutes)
}
// Record usage
await db.create($.UsageRecord, {
customerId: request.customerId,
serviceId: videoTranscodingService.id,
timestamp: new Date(),
units: minutes,
cost,
metadata: {
videoId: result.videoId,
resolution: request.inputs.resolution,
format: request.inputs.format,
},
})
// Deliver result
await send($.ServiceResult.deliver, {
requestId: request.id,
outputs: {
transcodedUrl: result.url,
thumbnailUrl: result.thumbnail,
duration: result.duration,
},
pricing: breakdown,
})
// Charge overage if applicable
if (cost > 0) {
await send($.Payment.charge, {
customerId: request.customerId,
amount: cost,
description: `Video Transcoding Overage - ${breakdown.overageMinutes} minutes`,
breakdown,
})
}
// Suggest upgrade if consistently hitting overage
if (usedMinutes > pkg.included.minutes * 1.5) {
const nextPackage = videoTranscodingService.pricing.packages[videoTranscodingService.pricing.packages.findIndex((p) => p.name === pkg.name) + 1]
if (nextPackage) {
await send($.Customer.notify, {
customerId: request.customerId,
type: 'package-upgrade-suggestion',
message: `You're using ${usedMinutes} minutes/month. Upgrade to ${nextPackage.name} for better value.`,
comparison: {
currentCost: pkg.monthlyFee + (usedMinutes - pkg.included.minutes) * pkg.overage.rate,
upgradeCost: nextPackage.monthlyFee,
savings: pkg.monthlyFee + (usedMinutes - pkg.included.minutes) * pkg.overage.rate - nextPackage.monthlyFee,
},
})
}
}
} catch (error) {
await send($.ServiceRequest.fail, {
requestId: request.id,
error: error.message,
})
}
})
async function transcodeVideo(inputs: any) {
// Simulate video transcoding
return {
videoId: `video_${Date.now()}`,
url: `https://cdn.example.com/video_${Date.now()}.mp4`,
thumbnail: `https://cdn.example.com/thumb_${Date.now()}.jpg`,
duration: 300, // 5 minutes
}
}Package Tier Value:
- Hobby (Free): 60 min included, $0.05/min overage
- 100 min usage = $2.00 (60 free + 40 × $0.05)
- Creator ($29/mo): 1,000 min included, $0.03/min overage
- 1,500 min usage = $44.00 ($29 + 500 × $0.03)
- Professional ($99/mo): 5,000 min included, $0.02/min overage
- 6,000 min usage = $119.00 ($99 + 1,000 × $0.02)
- Studio ($499/mo): 30,000 min included, $0.01/min overage
- 35,000 min usage = $549.00 ($499 + 5,000 × $0.01)
Pattern 7: Graduated Bulk Discounts
Offer increasing discounts at volume milestones:
const printingService = await $.Service.create({
name: 'Print-on-Demand Service',
type: $.ServiceType.Printing,
pricing: {
model: 'graduated-bulk',
basePrice: 10.0, // $10 per unit at base
discounts: [
{
quantity: 1,
discount: 0, // No discount
price: 10.0,
},
{
quantity: 50,
discount: 0.1, // 10% off at 50+
price: 9.0,
},
{
quantity: 100,
discount: 0.2, // 20% off at 100+
price: 8.0,
},
{
quantity: 500,
discount: 0.3, // 30% off at 500+
price: 7.0,
},
{
quantity: 1000,
discount: 0.4, // 40% off at 1,000+
price: 6.0,
},
{
quantity: 5000,
discount: 0.5, // 50% off at 5,000+
price: 5.0,
},
],
},
})
function calculateBulkPrice(
quantity: number,
discounts: any[]
): {
unitPrice: number
total: number
discount: number
savings: number
} {
// Find applicable discount tier
let applicableTier = discounts[0]
for (const tier of discounts) {
if (quantity >= tier.quantity) {
applicableTier = tier
}
}
const unitPrice = applicableTier.price
const total = quantity * unitPrice
const baseTotal = quantity * discounts[0].price
const savings = baseTotal - total
return {
unitPrice,
total,
discount: applicableTier.discount,
savings,
}
}
on($.ServiceRequest.created, async (request) => {
if (request.serviceId !== printingService.id) return
const quantity = request.inputs.quantity
try {
// Calculate pricing
const pricing = calculateBulkPrice(quantity, printingService.pricing.discounts)
// Process print order
const result = await processPrintOrder(request.inputs)
// Deliver result
await send($.ServiceResult.deliver, {
requestId: request.id,
outputs: {
orderId: result.orderId,
items: result.items,
estimatedShipDate: result.shipDate,
},
})
// Charge customer
await send($.Payment.charge, {
customerId: request.customerId,
amount: pricing.total,
description: `Print Order - ${quantity} units`,
breakdown: {
quantity,
unitPrice: pricing.unitPrice,
discount: `${(pricing.discount * 100).toFixed(0)}%`,
subtotal: quantity * printingService.pricing.basePrice,
discountAmount: pricing.savings,
total: pricing.total,
},
})
// Show next discount tier
const nextTier = printingService.pricing.discounts.find((d) => d.quantity > quantity)
if (nextTier) {
const additionalNeeded = nextTier.quantity - quantity
const nextSavings = quantity * (pricing.unitPrice - nextTier.price)
await send($.Customer.notify, {
customerId: request.customerId,
type: 'bulk-discount-opportunity',
message: `Order ${additionalNeeded} more units to unlock ${(nextTier.discount * 100).toFixed(0)}% discount`,
data: {
currentQuantity: quantity,
currentDiscount: pricing.discount,
nextTierQuantity: nextTier.quantity,
nextDiscount: nextTier.discount,
additionalUnitsNeeded: additionalNeeded,
potentialSavings: nextSavings,
},
})
}
} catch (error) {
await send($.ServiceRequest.fail, {
requestId: request.id,
error: error.message,
})
}
})
async function processPrintOrder(inputs: any) {
// Simulate print processing
return {
orderId: `order_${Date.now()}`,
items: inputs.quantity,
shipDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
}
}Graduated Bulk Pricing:
- 25 units = $250.00 ($10 each, no discount)
- 75 units = $675.00 ($9 each, 10% off, save $75)
- 250 units = $2,000.00 ($8 each, 20% off, save $500)
- 1,500 units = $9,000.00 ($6 each, 40% off, save $6,000)
- 10,000 units = $50,000.00 ($5 each, 50% off, save $50,000)
Pattern 8: Multi-Dimensional Tiering
Apply different tier structures to multiple dimensions:
const analyticsService = await $.Service.create({
name: 'Advanced Analytics Platform',
type: $.ServiceType.Analytics,
pricing: {
model: 'multi-dimensional-tiered',
dimensions: {
dataVolume: {
unit: 'gigabyte',
tiers: [
{ min: 0, max: 100, rate: 0.5 },
{ min: 100, max: 1000, rate: 0.4 },
{ min: 1000, max: Infinity, rate: 0.3 },
],
},
computeHours: {
unit: 'hour',
tiers: [
{ min: 0, max: 10, rate: 5.0 },
{ min: 10, max: 100, rate: 4.0 },
{ min: 100, max: Infinity, rate: 3.0 },
],
},
apiCalls: {
unit: 'call',
tiers: [
{ min: 0, max: 10000, rate: 0.001 },
{ min: 10000, max: 100000, rate: 0.0008 },
{ min: 100000, max: Infinity, rate: 0.0005 },
],
},
},
},
})
function calculateMultiDimensionalPrice(
usage: {
dataVolume: number
computeHours: number
apiCalls: number
},
dimensions: any
): {
total: number
breakdown: any
} {
const breakdown: any = {}
let total = 0
for (const [dimension, volume] of Object.entries(usage)) {
const tierConfig = dimensions[dimension]
const pricing = calculateTieredPrice(volume, tierConfig.tiers)
breakdown[dimension] = {
volume,
unit: tierConfig.unit,
cost: pricing.total,
tiers: pricing.breakdown,
}
total += pricing.total
}
return { total, breakdown }
}
on($.ServiceRequest.created, async (request) => {
if (request.serviceId !== analyticsService.id) return
try {
// Run analytics job
const result = await runAnalyticsJob(request.inputs)
// Calculate multi-dimensional pricing
const usage = {
dataVolume: result.dataProcessedGB,
computeHours: result.computeHours,
apiCalls: result.apiCalls,
}
const pricing = calculateMultiDimensionalPrice(usage, analyticsService.pricing.dimensions)
// Deliver result
await send($.ServiceResult.deliver, {
requestId: request.id,
outputs: {
results: result.data,
insights: result.insights,
visualizations: result.visualizations,
},
})
// Charge customer
await send($.Payment.charge, {
customerId: request.customerId,
amount: pricing.total,
description: 'Analytics Job',
breakdown: pricing.breakdown,
})
} catch (error) {
await send($.ServiceRequest.fail, {
requestId: request.id,
error: error.message,
})
}
})
async function runAnalyticsJob(inputs: any) {
// Simulate analytics processing
return {
data: { results: [] },
insights: ['Insight 1', 'Insight 2'],
visualizations: ['chart1.png', 'chart2.png'],
dataProcessedGB: 150,
computeHours: 25,
apiCalls: 15000,
}
}Multi-Dimensional Pricing Example:
- Data: 150 GB = $55 (100 @ $0.50 + 50 @ $0.40)
- Compute: 25 hours = $110 (10 @ $5 + 15 @ $4)
- API: 15,000 calls = $14 (10k @ $0.001 + 5k @ $0.0008)
- Total: $179
Advanced Patterns
Tier Forecasting
Help customers understand future costs:
async function forecastTierCosts(customerId: string, serviceId: string, projectedVolumes: number[]) {
const service = await db.findOne($.Service, { id: serviceId })
const historicalUsage = await db.query($.UsageRecord, {
where: { customerId, serviceId },
orderBy: { timestamp: 'desc' },
limit: 90, // Last 90 days
})
const averageDaily = historicalUsage.reduce((sum, u) => sum + u.units, 0) / 90
return projectedVolumes.map((volume) => {
const pricing = calculateTieredPrice(volume, service.pricing.tiers)
return {
volume,
cost: pricing.total,
averageRate: pricing.total / volume,
savings: volume * service.pricing.tiers[0].rate - pricing.total,
daysToReach: Math.ceil(volume / averageDaily),
breakdown: pricing.breakdown,
}
})
}Tier Optimization Recommendations
Suggest optimal usage patterns:
async function suggestTierOptimization(customerId: string, serviceId: string) {
const service = await db.findOne($.Service, { id: serviceId })
const usage = await getMonthlyUsage(customerId, serviceId)
const suggestions = []
// Check if customer is just below a tier threshold
for (let i = 0; i < service.pricing.tiers.length - 1; i++) {
const currentTier = service.pricing.tiers[i]
const nextTier = service.pricing.tiers[i + 1]
if (usage.total >= currentTier.min && usage.total < nextTier.min) {
const gap = nextTier.min - usage.total
const gapPercentage = (gap / usage.total) * 100
// If within 20% of next tier
if (gapPercentage <= 20) {
const currentCost = calculateTieredPrice(usage.total, service.pricing.tiers).total
const nextTierCost = calculateTieredPrice(nextTier.min, service.pricing.tiers).total
const additionalCost = nextTierCost - currentCost
const additionalUnits = gap
suggestions.push({
type: 'tier-threshold',
message: `You're ${gap} units away from ${nextTier.name} tier`,
analysis: {
currentUsage: usage.total,
currentCost,
nextTierThreshold: nextTier.min,
additionalUnitsNeeded: additionalUnits,
additionalCost,
newRate: nextTier.rate,
potentialSavingsPerUnit: currentTier.rate - nextTier.rate,
},
})
}
}
}
return suggestions
}Best Practices
1. Clear Tier Communication
Show customers exactly where they stand:
async function getTierStatus(customerId: string, serviceId: string) {
const service = await db.findOne($.Service, { id: serviceId })
const usage = await getCurrentPeriodUsage(customerId, serviceId)
const currentTier = service.pricing.tiers.find((t) => usage.total >= t.min && usage.total < t.max)
const nextTier = service.pricing.tiers.find((t) => t.min > usage.total)
return {
current: {
tier: currentTier.name,
usage: usage.total,
rate: currentTier.rate,
range: `${currentTier.min}-${currentTier.max} ${service.pricing.unit}s`,
},
next: nextTier
? {
tier: nextTier.name,
threshold: nextTier.min,
rate: nextTier.rate,
unitsToNextTier: nextTier.min - usage.total,
potentialSavings: (currentTier.rate - nextTier.rate) * usage.total,
}
: null,
progress: nextTier ? (usage.total / nextTier.min) * 100 : 100,
}
}2. Fair Tier Transitions
Handle month-to-month tier changes gracefully:
on($.BillingCycle.ended, async (cycle) => {
const customers = await db.query($.Customer, { status: 'active' })
for (const customer of customers) {
const usage = await getUsageForPeriod(customer.id, cycle.start, cycle.end)
// Determine tier for the full period
const tier = determineTierForUsage(usage.total)
// Apply tier rate retroactively to all usage
const cost = calculateTieredPrice(usage.total, tier.tiers).total
await send($.Invoice.create, {
customerId: customer.id,
period: { start: cycle.start, end: cycle.end },
amount: cost,
breakdown: {
usage: usage.total,
tier: tier.name,
calculation: 'end-of-period',
},
})
}
})3. Volume Commitment Benefits
Reward customers who commit to volume:
async function offerVolumeCommitment(customerId: string) {
const historicalUsage = await getHistoricalUsage(customerId, 6) // 6 months
const averageMonthly = historicalUsage.reduce((sum, m) => sum + m.usage, 0) / 6
// Offer commitment at 80% of average usage
const recommendedCommit = Math.floor(averageMonthly * 0.8)
const payAsYouGoRate = 0.1
const commitRate = 0.07 // 30% discount
const projectedSavings = (payAsYouGoRate - commitRate) * recommendedCommit * 12
return {
recommendation: {
monthlyCommit: recommendedCommit,
rate: commitRate,
discount: 0.3,
projectedAnnualSavings: projectedSavings,
},
comparison: {
currentAverageMonthly: averageMonthly,
currentEstimatedCost: averageMonthly * payAsYouGoRate,
commitCost: recommendedCommit * commitRate,
monthlySavings: averageMonthly * payAsYouGoRate - recommendedCommit * commitRate,
},
}
}Real-World Examples
Cloud Storage (AWS S3 Style)
const pricing = {
tiers: [
{ min: 0, max: 50000, rate: 0.023 }, // First 50 TB
{ min: 50000, max: 450000, rate: 0.022 }, // Next 450 TB
{ min: 450000, max: Infinity, rate: 0.021 }, // Over 500 TB
],
}
// 100 TB = $2,250/month
// 1 PB = $21,700/month (vs $23,000 flat rate)Email Service (SendGrid Style)
const pricing = {
tiers: [
{ threshold: 0, rate: 0.001 }, // $1 per 1,000
{ threshold: 50000, rate: 0.0008 }, // $0.80 per 1,000 at 50k+
{ threshold: 100000, rate: 0.0006 }, // $0.60 per 1,000 at 100k+
],
}
// 75,000 emails = $67.50/month
// 250,000 emails = $182.50/monthAPI Platform (Stripe Style)
const pricing = {
tiers: [
{ min: 0, max: 1000000, rate: 0.029 }, // 2.9% + $0.30
{ min: 1000000, max: Infinity, rate: 0.027 }, // 2.7% for high volume
],
fixed: 0.3,
}
// $100k processed = $3,200 in fees
// $10M processed = $272,000 in fees (save $20k vs flat rate)Next Steps
- Hybrid Pricing → - Combine multiple models
- Subscription Pricing → - Recurring revenue
- Per-Use Pricing → - Usage-based billing
- Monetization Overview → - Compare all models
Resources
- Building Services → - Implement tiered pricing
- Best Practices → - Optimize your tiers
- Deployment → - Launch your service