- Content
Managing Subscriptions Add-Ons with Recurly API
Overview
In this guide we’ll walk through various methods for managing Subscription Add-Ons programmatically via Recurly API. The following use cases will be covered:
- Attaching new Add-Ons to a Subscription
- Modifying existing Add-Ons to a Subscription
- Removing Add-Ons from a Subscription
To get the most out of this guide, it’s recommended that you take a look at our product documentation for Subscription Changes, and also review the Subscription Management Guide and the Purchases Guide.
Estimated Completion time
1 Hour
Scenario Setup
Throughout this guide, we will be using a video streaming platform as an example scenario. The business offers a core video streaming plan which provides access for 10 users to each view 100 videos / month on the platform.
There are 4 Add-Ons that can be included with the Plan when creating the Subscription:
- Additional Users
- Higher Video Quality
- Additional Videos Per User
- Premium Content
There is an important distinction between an Add-On that is created with the Create Plan Add-On/Create Plan endpoint (a Plan Add-On) and an Add-On that has been added to a Subscription (a Subscription Add-On). The former can be thought of as a blueprint for creating instances of the latter.
Managing Subscription Add-Ons
The Create Subscription Change endpoint can be used to add, remove, and modify the Subscription’s Add-Ons. Add-Ons are managed via the add_ons
section of the request body. Each object defined in the add_ons
array must include either an id
or a code
at the minimum.
Special care should be taken when providing a value for the add_ons
field. All existing Add-Ons must be included or else they will be removed.
Additionally, in Recurly API v2019-10-10
, exlcuding the add_ons
section of the request body is equivalent of specifying an empty array. As such, failing to include add_ons
will remove all Add-Ons from the Subscription.
The attributes of a Subscription Add-On (quantity, unit_amount, tiers, and revenue_schedule_type) can be modified without impacting the original Plan Add-On. Likewise, a Plan Add-On can be updated after the creation of a Subscription Add-On and the existing Subscription Add-On will not be affected.
Subscription Add-On id vs Plan Add-On code:
- The Subscription Add-On
id
is used to preserve or modify an existing Subscription Add-On. - The Plan Add-On
code
is used to attach a new Subscription Add-On or reset an existing Subscription Add-On.
Supplying both the id
and code
in the request will be treated as if only the id
were passed.
Attach New Add-Ons
New Add-Ons can be attached to the Subscription by providing a Plan Add-On code
. Additional customizations of the Plan Add-On attributes can also be supplied at the same time.
For these examples, we are assuming that we have an existing Subscription. We want to attach four Plan Add-Ons with codes: additional-users
, higher-quality
, additional-videos
, and premium-content
:
Ruby
Node.js
Python
Java
Dotnet
PHP
change = @client.create_subscription_change(
subscription_id: subscription_id,
body: {
timeframe: "now",
add_ons: [
{ code: "additional-users" },
{ code: "higher-quality", quantity: 2 },
{ code: "additional-videos" },
{ code: "premium-content" }
]
}
)
puts "Created subscription change: #{change.id}"
const subscriptionChangeCreate = {
timeframe: 'now',
add_ons: [
{ code: "additional-users" },
{ code: "higher-quality", quantity: 2 },
{ code: "additional-videos" },
{ code: "premium-content" }
]
}
const change = await client.createSubscriptionChange(subscriptionId, subscriptionChangeCreate)
console.log('Created subscription change: ', change.id)
sub_change_create = {
timeframe: "now",
add_ons: [
{ code: "additional-users" },
{ code: "higher-quality", quantity: 2 },
{ code: "additional-videos" },
{ code: "premium-content" }
]
}
change = client.create_subscription_change(subscription_id, sub_change_create)
print("Created subscription change: %s" % change.id)
SubscriptionChangeCreate changeCreate = new SubscriptionChangeCreate();
changeCreate.setTimeframe("now");
List<SubscriptionAddOnUpdate> addOns = new ArrayList<>();
addOn1 = new SubscriptionAddOnUpdate()
addOn1.setCode("additional-users")
addOns.add(addOn1)
addOn2 = new SubscriptionAddOnUpdate()
addOn2.setCode("higher-quality")
addOn2.setQuantity(2)
addOns.add(addOn2)
addOn3 = new SubscriptionAddOnUpdate()
addOn3.setCode("additional-videos")
addOns.add(addOn3)
addOn4 = new SubscriptionAddOnUpdate()
addOn4.setCode("premium-content")
addOns.add(addOn4)
changeCreate.setAddOns(addOns)
SubscriptionChange change = client.createSubscriptionChange(subscriptionId, changeCreate);
System.out.println("Created subscription change: " + change.getId());
var changeReq = new SubscriptionChangeCreate()
{
Timeframe = "now",
AddOns = new List<SubscriptionAddOnUpdate>() {
new SubscriptionAddOnUpdate() {
Code = "additional-users"
},
new SubscriptionAddOnUpdate() {
Code = "higher-quality",
Quantity: 2
},
new SubscriptionAddOnUpdate() {
Code = "additional-videos",
},
new SubscriptionAddOnUpdate() {
Code = "premium-content",
}
}
};
SubscriptionChange change = client.CreateSubscriptionChange(subscriptionId, changeReq);
Console.WriteLine($"Created subscription change: {change.Id}");
$change_create = array(
"timeframe" => "now",
"add_ons" => [
[ "code" => "additional-users" ],
[ "code" => "higher-quality", "quantity" => 2 ],
[ "code" => "additional-videos" ],
[ "code" => "premium-content" ]
]
);
$change = $client->createSubscriptionChange($subscription_id, $change_create);
echo "Created subscription change: {$change->getId()}" . PHP_EOL;
After the request has completed, there will be four Subscription Add-Ons attached to the Subscription. We will use these as the starting point for the other examples in this section. A simplified representation of these Subscription Add-Ons is below.
[
{ "id": "n1d523w2ekth", "quantity": 1, "add_on": { "code": "additional-users" } },
{ "id": "n1cqfmlawfnv", "quantity": 2, "add_on": { "code": "higher-quality" } },
{ "id": "n1f9sicpgyc7", "quantity": 1, "add_on": { "code": "additional-videos" } },
{ "id": "n1e8g6s8d2ep", "quantity": 1, "add_on": { "code": "premium-content" } }
]
Modify Existing Add-Ons
There are two strategies that can be employed when updating an existing Subscription Add-On:
Passing The Subscription Add-On Id
If the Subscription Add-On’s id
is provided in the request, Recurly API will update the existing Subscription Add-On with the provided updates.
Any changes made to the Plan Add-On since the creation of the Subscription Add-On will not be updated.
In the below examples, we will be adjusting the quantity
of the third Subscription Add-On, n1f9sicpgyc7
.
Ruby
Node.js
Python
Java
Dotnet
PHP
change = @client.create_subscription_change(
subscription_id: subscription_id,
body: {
timeframe: "now",
add_ons: [
{ id: "n1d523w2ekth" },
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7", quantity: 2 },
{ id: "n1e8g6s8d2ep" }
]
}
)
puts "Created subscription change: #{change.id}"
const subscriptionChangeCreate = {
timeframe: 'now',
add_ons: [
{ id: "n1d523w2ekth" },
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7", quantity: 2 },
{ id: "n1e8g6s8d2ep" }
]
}
const change = await client.createSubscriptionChange(subscriptionId, subscriptionChangeCreate)
console.log('Created subscription change: ', change.id)
sub_change_create = {
timeframe: "now",
add_ons: [
{ id: "n1d523w2ekth" },
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7", quantity: 2 },
{ id: "n1e8g6s8d2ep" }
]
}
change = client.create_subscription_change(subscription_id, sub_change_create)
print("Created subscription change: %s" % change.id)
SubscriptionChangeCreate changeCreate = new SubscriptionChangeCreate();
changeCreate.setTimeframe("now");
List<SubscriptionAddOnUpdate> addOns = new ArrayList<>();
SubscriptionAddOnUpdate addOn1 = new SubscriptionAddOnUpdate()
addOn1.setId("n1d523w2ekth")
addOns.add(addOn1)
SubscriptionAddOnUpdate addOn2 = new SubscriptionAddOnUpdate()
addOn2.setId("n1cqfmlawfnv")
addOns.add(addOn2)
SubscriptionAddOnUpdate addOn3 = new SubscriptionAddOnUpdate()
addOn3.setId("n1f9sicpgyc7")
addOn3.setQuantity(2)
addOns.add(addOn3)
SubscriptionAddOnUpdate addOn4 = new SubscriptionAddOnUpdate()
addOn4.setId("n1e8g6s8d2ep")
addOns.add(addOn4)
changeCreate.setAddOns(addOns)
SubscriptionChange change = client.createSubscriptionChange(subscriptionId, changeCreate);
System.out.println("Created subscription change: " + change.getId());
var changeReq = new SubscriptionChangeCreate()
{
Timeframe = "now",
AddOns = new List<SubscriptionAddOnUpdate>() {
new SubscriptionAddOnUpdate() {
Id = "n1d523w2ekth"
},
new SubscriptionAddOnUpdate() {
Id = "n1cqfmlawfnv"
},
new SubscriptionAddOnUpdate() {
Id = "n1f9sicpgyc7",
Quantity: 2
},
new SubscriptionAddOnUpdate() {
Id = "n1e8g6s8d2ep"
}
}
};
SubscriptionChange change = client.CreateSubscriptionChange(subscriptionId, changeReq);
Console.WriteLine($"Created subscription change: {change.Id}");
$change_create = array(
"timeframe" => "now",
"add_ons" => [
[ "id" => "n1d523w2ekth" ],
[ "id" => "n1cqfmlawfnv" ],
[ "id" => "n1f9sicpgyc7", "quantity" => 2 ],
[ "id" => "n1e8g6s8d2ep" ]
]
);
$change = $client->createSubscriptionChange($subscription_id, $change_create);
echo "Created subscription change: {$change->getId()}" . PHP_EOL;
Remember that we must include the other three Subscription Add-Ons to avoid deleting them.
Passing The Plan Add-On Code
If the Plan Add-On’s code
is passed, Recurly API will effectively reset the existing Subscription Add-On’s attributes to those of the Plan Add-On. Any additional attributes supplied along with the code
will be applied to the new Subscription Add-On.
If the Plan Add-On has been updated since the original Subscription Add-On was created, then the Subscription Add-On will be updated to the attributes of the current Plan Add-On.
In the below examples, we will be adjusting the quantity
of the fourth Subscription Add-On which is based on the Plan Add-On with code, premium-content
.
Ruby
Node.js
Python
Java
Dotnet
PHP
change = @client.create_subscription_change(
subscription_id: subscription_id,
body: {
timeframe: "now",
add_ons: [
{ id: "n1d523w2ekth" },
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7" },
{ code: "premium-content", quantity: 2 }
]
}
)
puts "Created subscription change: #{change.id}"
const subscriptionChangeCreate = {
timeframe: 'now',
add_ons: [
{ id: "n1d523w2ekth" },
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7" },
{ code: "premium-content", quantity: 2 }
]
}
const change = await client.createSubscriptionChange(subscriptionId, subscriptionChangeCreate)
console.log('Created subscription change: ', change.id)
sub_change_create = {
timeframe: "now",
add_ons: [
{ id: "n1d523w2ekth" },
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7" },
{ code: "premium-content", quantity: 2 }
]
}
change = client.create_subscription_change(subscription_id, sub_change_create)
print("Created subscription change: %s" % change.id)
SubscriptionChangeCreate changeCreate = new SubscriptionChangeCreate();
changeCreate.setTimeframe("now");
List<SubscriptionAddOnUpdate> addOns = new ArrayList<>();
SubscriptionAddOnUpdate addOn1 = new SubscriptionAddOnUpdate()
addOn1.setId("n1d523w2ekth")
addOns.add(addOn1)
SubscriptionAddOnUpdate addOn2 = new SubscriptionAddOnUpdate()
addOn2.setId("n1cqfmlawfnv")
addOns.add(addOn2)
SubscriptionAddOnUpdate addOn3 = new SubscriptionAddOnUpdate()
addOn3.setId("n1f9sicpgyc7")
addOns.add(addOn3)
SubscriptionAddOnUpdate addOn4 = new SubscriptionAddOnUpdate()
addOn4.setCode("premium-content")
addOn4.setQuantity(2)
addOns.add(addOn4)
changeCreate.setAddOns(addOns)
SubscriptionChange change = client.createSubscriptionChange(subscriptionId, changeCreate);
System.out.println("Created subscription change: " + change.getId());
var changeReq = new SubscriptionChangeCreate()
{
Timeframe = "now",
AddOns = new List<SubscriptionAddOnUpdate>() {
new SubscriptionAddOnUpdate() {
Id = "n1d523w2ekth"
},
new SubscriptionAddOnUpdate() {
Id = "n1cqfmlawfnv"
},
new SubscriptionAddOnUpdate() {
Id = "n1f9sicpgyc7"
},
new SubscriptionAddOnUpdate() {
Code = "premium-content",
Quantity: 2
}
}
};
SubscriptionChange change = client.CreateSubscriptionChange(subscriptionId, changeReq);
Console.WriteLine($"Created subscription change: {change.Id}");
$change_create = array(
"timeframe" => "now",
"add_ons" => [
[ "id" => "n1d523w2ekth" ],
[ "id" => "n1cqfmlawfnv" ],
[ "id" => "n1f9sicpgyc7" ],
[ "code" => "premium-content", "quantity" => 2 ]
]
);
$change = $client->createSubscriptionChange($subscription_id, $change_create);
echo "Created subscription change: {$change->getId()}" . PHP_EOL;
Remember that we must include the other three Subscription Add-Ons to avoid deleting them.
Removing Add-Ons
An Add-On can be removed from a Subscription by both including the add_ons
array in the Create Subscription Change request and excluding the Subscription Add-On id
/Plan Add-On code
.
In the below examples, we will be removing the first Subscription Add-On, n1d523w2ekth
.
Ruby
Node.js
Python
Java
Dotnet
PHP
change = @client.create_subscription_change(
subscription_id: subscription_id,
body: {
timeframe: "now",
add_ons: [
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7" },
{ id: "n1e8g6s8d2ep" }
]
}
)
puts "Created subscription change: #{change.id}"
const subscriptionChangeCreate = {
timeframe: 'now',
add_ons: [
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7" },
{ id: "n1e8g6s8d2ep" }
]
}
const change = await client.createSubscriptionChange(subscriptionId, subscriptionChangeCreate)
console.log('Created subscription change: ', change.id)
sub_change_create = {
timeframe: "now",
add_ons: [
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7" },
{ id: "n1e8g6s8d2ep" }
]
}
change = client.create_subscription_change(subscription_id, sub_change_create)
print("Created subscription change: %s" % change.id)
SubscriptionChangeCreate changeCreate = new SubscriptionChangeCreate();
changeCreate.setTimeframe("now");
List<SubscriptionAddOnUpdate> addOns = new ArrayList<>();
SubscriptionAddOnUpdate addOn2 = new SubscriptionAddOnUpdate()
addOn2.setId("n1cqfmlawfnv")
addOns.add(addOn2)
SubscriptionAddOnUpdate addOn3 = new SubscriptionAddOnUpdate()
addOn3.setId("n1f9sicpgyc7")
addOns.add(addOn3)
SubscriptionAddOnUpdate addOn4 = new SubscriptionAddOnUpdate()
addOn4.setId("n1e8g6s8d2ep")
addOns.add(addOn4)
changeCreate.setAddOns(addOns)
SubscriptionChange change = client.createSubscriptionChange(subscriptionId, changeCreate);
System.out.println("Created subscription change: " + change.getId());
var changeReq = new SubscriptionChangeCreate()
{
Timeframe = "now",
AddOns = new List<SubscriptionAddOnUpdate>() {
new SubscriptionAddOnUpdate() {
Id = "n1cqfmlawfnv"
},
new SubscriptionAddOnUpdate() {
Id = "n1f9sicpgyc7"
},
new SubscriptionAddOnUpdate() {
Id = "n1e8g6s8d2ep"
}
}
};
SubscriptionChange change = client.CreateSubscriptionChange(subscriptionId, changeReq);
Console.WriteLine($"Created subscription change: {change.Id}");
$change_create = array(
"timeframe" => "now",
"add_ons" => [
[ "id" => "n1cqfmlawfnv" ],
[ "id" => "n1f9sicpgyc7" ],
[ "id" => "n1e8g6s8d2ep" ]
]
);
$change = $client->createSubscriptionChange($subscription_id, $change_create);
echo "Created subscription change: {$change->getId()}" . PHP_EOL;
Remember that we must include the other three Subscription Add-Ons to avoid deleting them.
Adding, Modifying by Id, Modifying by Code, and Removing Add-Ons
All of the above operations can be consolidated into a single request. There is no restriction that each action be done in it’s own request.
In the below examples, we will:
- Remove the first Subscription Add-On,
n1d523w2ekth
, by excluding it from the request. - Adjust the
quantity
of the third Subscription Add-On using it’s id:n1f9sicpgyc7
- Adjust the
quantity
of the fourth Subscription Add-On using it’s Plan Add-On code:premium-content
.
Ruby
Node.js
Python
Java
Dotnet
PHP
change = @client.create_subscription_change(
subscription_id: subscription_id,
body: {
timeframe: "now",
add_ons: [
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7", quantity: 2 },
{ code: "premium-content", quantity: 2 }
]
}
)
puts "Created subscription change: #{change.id}"
const subscriptionChangeCreate = {
timeframe: 'now',
add_ons: [
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7", quantity: 2 },
{ code: "premium-content", quantity: 2 }
]
}
const change = await client.createSubscriptionChange(subscriptionId, subscriptionChangeCreate)
console.log('Created subscription change: ', change.id)
sub_change_create = {
timeframe: "now",
add_ons: [
{ id: "n1cqfmlawfnv" },
{ id: "n1f9sicpgyc7", quantity: 2 },
{ code: "premium-content", quantity: 2 }
]
}
change = client.create_subscription_change(subscription_id, sub_change_create)
print("Created subscription change: %s" % change.id)
SubscriptionChangeCreate changeCreate = new SubscriptionChangeCreate();
changeCreate.setTimeframe("now");
List<SubscriptionAddOnUpdate> addOns = new ArrayList<>();
SubscriptionAddOnUpdate addOn2 = new SubscriptionAddOnUpdate()
addOn2.setId("n1cqfmlawfnv")
addOns.add(addOn2)
SubscriptionAddOnUpdate addOn3 = new SubscriptionAddOnUpdate()
addOn3.setId("n1f9sicpgyc7")
addOn3.setQuantity(2)
addOns.add(addOn3)
SubscriptionAddOnUpdate addOn4 = new SubscriptionAddOnUpdate()
addOn4.setCode("premium-content")
addOn4.setQuantity(2)
addOns.add(addOn4)
changeCreate.setAddOns(addOns)
SubscriptionChange change = client.createSubscriptionChange(subscriptionId, changeCreate);
System.out.println("Created subscription change: " + change.getId());
var changeReq = new SubscriptionChangeCreate()
{
Timeframe = "now",
AddOns = new List<SubscriptionAddOnUpdate>() {
new SubscriptionAddOnUpdate() {
Id = "n1cqfmlawfnv"
},
new SubscriptionAddOnUpdate() {
Id = "n1f9sicpgyc7",
Quantity: 2
},
new SubscriptionAddOnUpdate() {
Code = "premium-content",
Quantity: 2
}
}
};
SubscriptionChange change = client.CreateSubscriptionChange(subscriptionId, changeReq);
Console.WriteLine($"Created subscription change: {change.Id}");
$change_create = array(
"timeframe" => "now",
"add_ons" => [
[ "id" => "n1cqfmlawfnv" ],
[ "id" => "n1f9sicpgyc7", "quantity" => 2 ],
[ "code" => "premium-content", "quantity" => 2 ]
]
);
$change = $client->createSubscriptionChange($subscription_id, $change_create);
echo "Created subscription change: {$change->getId()}" . PHP_EOL;