Tiered Pricing
Updated June 07, 2016
Tiered Pricing is a means of providing products or services at different price points. In this type of pricing model, the product rates are bundled into separate pricing tiers. Once a tier is filled up, the product will move to the next tier and a different price will be charged.

If you're looking to set up Volume Pricing, please refer to our guide here.
Use Case 1: Subscription created with 10 units
When a Subscription is created with a quantity of 10 units, all units will be charged $15, as the number of units would fall in the Tier 1 range.

Use Case 2: Subscriptions created with 50 units
When a Subscription is created with a quantity of 50 units, the price would be calculated across all four tiers.


Here's a quick guide on how to set up Tiered Pricing using API and JSON payload.
Step 1
Create a $0 Base Plan (e.g. Plan name Cloud Server) with Flat Fee pricing in your Chargebee site. The only purpose of this Plan would be to define the billing frequency of the product (monthly, quarterly, etc.).
Step 2
Create a Recurring Addon (quantity based) for every tier as shown below. Ensure that the Addon frequency matches the frequency of the Plan.
Step 3
Add the JSON Meta data to the $0 Base Plan. Chargebee has the Meta data feature that can be used to store additional data at different levels (Plans, Subscriptions, Customers etc). Add JSON Meta data to the $0 Base Plan, to establish a relationship between "the unit range and the Addons.
{"tiered_pricing": [
{
"addon_id": "cloud_server_01_20",
"start_range": 1,
"end_range": 20
},
{
"addon_id": "cloud_server_21_25",
"start_range": 21,
"end_range": 25
},
{
"addon_id": "cloud_server_26_30",
"start_range": 26,
"end_range": 30
},
{
"addon_id": "cloud_server_31",
"start_range": 31
}
]}
function tieredPricingUpdatePlanMetaData($planId) {
$tieredPricing = array( "tiered_pricing" => array(
array("addon_id" => $planId . "_01_20",
"start_range" => 1,
"end_range" => 20),
array("addon_id" => $planId . "_21_25",
"start_range" => 21,
"end_range" => 25),
array("addon_id" => $planId . "_26_30",
"start_range" => 26, "end_range" => 30),
array("addon_id" => $planId . "_31",
"start_range" => 31)
)
);
$planResult = ChargeBee_Plan::update($planId,
array("metaData" => json_encode($tieredPricing)));
}
def tiered_pricing_update_plan_meta_data(plan_id)
tiered_pricing = {:tiered_pricing => [
{ :addon_id => "#{plan_id}_01_20",
:start_range => 1,
:end_range => 20
},
{ :addon_id => "#{plan_id}_21_25",
:start_range => 21,
:end_range => 25
},
{ :addon_id => "#{plan_id}_26_30",
:start_range => 26,
:end_range => 30
},
{ :addon_id => "#{plan_id}_31",
:start_range => 31
}
]}
result = ChargeBee::Plan.update(plan_id, {
:meta_data => tiered_pricing.to_json
})
end
def tiered_pricing_update_plan_meta_data(plan_id):
tiered_pricing = {
"tiered_pricing" : [
{ "addon_id" : "cloud_server_01_20",
"start_range" : 1,
"end_range" : 20
},
{ "addon_id" : "cloud_server_21_25",
"start_range" : 21,
"end_range" : 25
},
{ "addon_id" : "cloud_server_26_30",
"start_range" : 26,
"end_range" : 30
},
{ "addon_id" : "cloud_server_31",
"start_range" : 31
}
]}
plan_result = chargebee.Plan.update(plan_id,
{"meta_data": json.dumps(tiered_pricing)})
function tieredPricingUpdatePlanMetaData(planId) {
var tiered_pricing = { "tiered_pricing": [
{ "addon_id" : planId + "_01_20",
"start_range": 1,
"end_range": 20
},
{ "addon_id" : planId + "_21_25",
"start_range": 21,
"end_range": 25
},
{ "addon_id" : planId + "_26_30",
"start_range": 26,
"end_range": 30
},
{ "addon_id" : planId + "_31",
"start_range": 31,
}]
};
chargebee.plan.update(planId, { meta_data: tiered_pricing })
.request(function(error, result) {
if(error){
console.log(error);
}else{
console.log(result);
}
});
}
public void tieredPricingUpdatePlanMetaData(String planId)
throws JSONException, IOException {
JSONObject metaData = new JSONObject();
JSONArray arr = new JSONArray();
arr.put(addonObj(planId + "_01_20", 1, 20));
arr.put(addonObj(planId + "_21_25", 21, 25));
arr.put(addonObj(planId + "_26_30", 26, 30));
arr.put(addonObj(planId + "_31", 31, 0));
metaData.put("tiered_pricing", arr);
Result planResult = Plan.update(planId)
.metaData(metaData).request();
}
public JSONObject addonObj(String addonId, int startRange,
int endRange) throws JSONException {
return new JSONObject().put("addon_id", addonId)
.put("start_range", startRange)
.put("end_range", endRange);
}
public void tieredPricingUpdatePlanMetaData(String planId){
JObject metaData = new JObject();
JArray arr = new JArray();
arr.Add(addonObj(planId + "_01_20", 1, 20));
arr.Add(addonObj(planId + "_21_25", 21, 25));
arr.Add(addonObj(planId + "_26_30", 26, 30));
arr.Add(addonObj(planId + "_31", 31, 0));
metaData.Add(new JProperty("tiered_pricing", arr));
EntityResult planResult = Plan.Update(planId)
.MetaData(metaData).Request();
}
public JObject addonObj(String addonId, int startRange,
int endRange) {
return new JObject (new JProperty("addon_id",addonId),
new JProperty("start_range",startRange),
new JProperty("end_range",endRange));
}
Step 4
Create a Subscription with the Tiered Plan and Addons
Based on the Plan's metadata, pick the appropriate Addon(s) and create the Subscription with the required range. The Plan's metadata can be queried before Subscription creation to receive the Addon and Tier details.
How to change quantity for Subscriptions with Tiered Pricing
When a Subscription's quantity has to be changed, you can create the new set of Addons using the Update Subscription API.
Let's consider the following scenario:
A Subscription is created with a quantity of 25 units. The price for this, hence, will be calculated using 2 tiers.
The Customer now wants the Subscription's quantity to be changed from
25 to 5 units.
In this case, call the Update a Subscription API with replace_addon_list parameter set to true and pass the Addon quantities as per the change in Subscription.

function tieredPricingUpdateSubscription($planId,
$subscribeQty, $subscriptionId) {
$planResult = ChargeBee_Plan::retrieve($planId);
$metaData = $planResult->plan()->metaData;
$tieredPricing = $metaData["tiered_pricing"];
$addons = array();
for($i=0; $i < count($tieredPricing); $i++) {
$addonObj = $tieredPricing[$i];
$addonId = $addonObj["addon_id"];
$startRange = $addonObj["start_range"];
$endRange = isset($addonObj["end_range"]) ?
$addonObj["end_range"] : 0;
if($subscribeQty < $startRange) {
break;
}
$addonQty = 0;
if($subscribeQty <= $endRange || $endRange == 0 ) {
$addonQty = $subscribeQty - $startRange;
} else {
$addonQty = $endRange - $startRange;
}
$addonQty = $addonQty + 1;
$addons[] = array("id" => $addonId,
"quantity"=> $addonQty);
}
$result = ChargeBee_Subscription::update($subscriptionId,
array("replaceAddonList"=> "true",
"addons" => $addons));
}
def tiered_pricing_update_subscription(plan_id,
subscription_id, subscribe_qty)
plan_result = ChargeBee::Plan.retrieve(plan_id)
meta_data = plan_result.plan.meta_data
tiered_pricing = meta_data[:tiered_pricing]
addons = Array.new
tiered_pricing.each do |addon_obj|
addon_id = addon_obj[:addon_id]
start_range = addon_obj[:start_range]
end_range = addon_obj[:end_range]
if subscribe_qty < start_range
break
end
addon_qty = 0
if end_range == nil || subscribe_qty <= end_range
addon_qty = subscribe_qty - start_range
elsif
addon_qty = end_range - start_range
end
addon_qty = addon_qty + 1
addons.push({:id => addon_id, :quantity => addon_qty })
end
result = ChargeBee::Subscription.update(subscription_id,
{:replace_addon_list => "true",
:addons => addons})
end
def tiered_pricing_update_subscription(plan_id,
subscription_id, subscribe_qty):
plan_result = chargebee.Plan.retrieve(plan_id)
meta_data = plan_result.plan.meta_data
tiered_pricing = meta_data["tiered_pricing"]
addons = []
for addon_obj in tiered_pricing:
addon_id = addon_obj.get("addon_id")
start_range = addon_obj.get("start_range")
end_range = addon_obj.get("end_range", None)
addon_qty = 0
if subscribe_qty < start_range:
break
if end_range == None or subscribe_qty <= end_range:
addon_qty = subscribe_qty - start_range
else:
addon_qty = end_range - start_range
addon_qty = addon_qty + 1
addons.append({"id": addon_id, "quantity" : addon_qty})
result = chargebee.Subscription.update(subscription_id,
{"replace_addon_list" : "true",
"addons" : addons})
function tieredPricingUpdateSubscription(planId,
subscribeQty, subscriptionId ) {
chargebee.plan.retrieve(planId)
.request(function(planError, planResult) {
if(planError) {
console.log(planError);
} else {
var metaData = planResult.plan.meta_data;
var tieredPricing = metaData.tiered_pricing;
var addons = [];
for(var i=0; i < tieredPricing.length; i++) {
var addonObj = tieredPricing[i];
var addonId = addonObj.addon_id
var startRange = addonObj.start_range
var endRange = addonObj.end_range
var addonQty = 0;
if(subscribeQty < startRange) {
break;
}
if( typeof(endRange) === 'undefined' ||
subscribeQty <= endRange) {
addonQty = subscribeQty - startRange;
} else {
addonQty = endRange - startRange;
}
addonQty = addonQty + 1;
addons.push({ "id" : addonId, "quantity" : addonQty})
}
chargebee.subscription.update(subscriptionId,
{ "replace_addon_list" : "true",
"addons" : addons })
.request(function(error, result){
if(error) {
console.log(error);
} else {
console.log(result);
}
})
}
})
}
public void tieredPricingUpdateSubscription(String planId,
int subscribeQty, String subscriptionId)
throws Exception {
Result planResult = Plan.retrieve(planId).request();
JSONArray tieredPricing = planResult.plan().metaData()
.getJSONArray("tiered_pricing");
Subscription.UpdateRequest updateRequest = Subscription
.update(subscriptionId);
int addonIndex = 0;
for(int i=0;i < tieredPricing.length(); i++) {
JSONObject obj = (JSONObject) tieredPricing.get(i);
String addonId = obj.getString("addon_id");
int startRange = obj.getInt("start_range");
int endRange = obj.getInt("end_range");
if(subscribeQty < startRange) {
break;
}
int addonQty = 0;
if(subscribeQty <= endRange || endRange == 0) {
addonQty = subscribeQty - startRange;
} else {
addonQty = endRange - startRange;
}
addonQty = addonQty + 1;
updateRequest.addonId(addonIndex, addonId)
.addonQuantity(addonIndex, addonQty);
addonIndex++;
}
Result result = updateRequest.replaceAddonList(true)
.request();
}
public void tieredPricingUpdateSubscription(String planId,
int subscribeQty,String subscriptionId) {
EntityResult planResult = Plan.Retrieve(planId)
.Request();
JArray tieredPricing = planResult.Plan
.MetaData ["tiered_pricing"].Value<JArray>();
Subscription.UpdateRequest updateRequest = Subscription
.Update(subscriptionId);
int addonIndex = 0;
for(int i=0;i < tieredPricing.Count; i++) {
JObject obj = (JObject)tieredPricing [i];
String addonId = (string)obj ["addon_id"];
int startRange = (int)obj ["start_range"];
int endRange = (int)obj ["end_range"];
if(subscribeQty < startRange) {
break;
}
int addonQty = 0;
if(subscribeQty <= endRange || endRange == 0) {
addonQty = subscribeQty - startRange;
} else {
addonQty = endRange - startRange;
}
addonQty = addonQty + 1;
updateRequest.AddonId(addonIndex, addonId)
.AddonQuantity(addonIndex, addonQty);
addonIndex++;
}
EntityResult result = updateRequest
.ReplaceAddonList(true).Request();
}