Add and co-term additional license at pro-rated price

Overview

This guide shows you how to implement the Get Subscription and Update Subscription Item endpoints to add an additional subscription seat at a discounted price and align it to the existing subscription renewal date.

Use case

  1. A customer signs up for your Cloud Storage service on May 13, 2026, and purchases one annual seat for $1200.00.
  2. The customer receives an offer to add a second seat at a discounted price of $600.00 per year.
  3. The customer accepts the offer on your customer self-service page. The additional seat is added immediately and aligned to the existing subscription renewal date.

Result

On May 13, 2027, the customer renews both seats for a total of $1800.00:

  • $1200.00 for the original seat
  • $600.00 for the additional seat
📘

Note

This example assumes that incremental volume pricing is configured so that the second seat renews at the discounted price.

Implement the API endpoints

Use the Get Subscription endpoint to retrieve the current renewal date, then use Update Subscription Item endpoint to add the additional seat.

Before you start

Make sure that:


🚧

Important

Get the customer's consent before making changes to a subscription.

To avoid chargebacks and customer inquiries, it is also essential that you coordinate all price increases with Client Experience.

In the European Economic Area (EEA), Strong Customer Authentication (SCA) is required for recurring electronic payments when the amount changes. This means that some of your customers will have to authenticate their payment, which in turn might impact the renewal success rate.

For more information, see Best Practices: Obtain Customer Consent.


Step 1: Retrieve the current renewal date

If the API call is formatted as described below, it will:

  • Return the current renewal pricing for the subscription.
  • Return the next billing date in the NextBillingDate field.
  • Not change any subscription data.

ParameterTypeRequiredExampleNotes
SubscriptionIdstrYesS68841753The unique identifier of the subscription.

Request

curl --location 'https://rest.cleverbridge.com/subscription/getsubscription?subscriptionId=S68841753' \
--header 'Accept: application/json' \
--header 'Authorization: Basic YOUR_BASE64_ENCODED_CREDENTIALS' \
import http.client

conn = http.client.HTTPSConnection("rest.cleverbridge.com")
payload = ''
headers = {
  'Accept': 'application/json',
  'Authorization': 'Basic YOUR_BASE64_ENCODED_CREDENTIALS'
}
conn.request("GET", "/subscription/getsubscription?subscriptionId=S68841753", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
var request = require('request');
var options = {
  'method': 'GET',
  'url': 'https://rest.cleverbridge.com/subscription/getsubscription?subscriptionId=S68841753',
  'headers': {
    'Accept': 'application/json',
    'Authorization': 'Basic YOUR_BASE64_ENCODED_CREDENTIALS'
  }
};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
Unirest.setTimeouts(0, 0);
HttpResponse<String> response = Unirest.get("https://rest.cleverbridge.com/subscription/getsubscription?subscriptionId=S68841753")
  .header("Accept", "application/json")
  .header("Authorization", "Basic YOUR_BASE64_ENCODED_CREDENTIALS")
  .asString();

Response

{
  "Subscription": {
    "Id": 68841753,
    "NextBillingDate": "2027-05-13T10:28:42.344357",
    "Items": [
      {
        "ProductId": 294835,
        "ProductName": "Cloudify Storage A",
        "Quantity": 1,
        "RunningNo": 1,
        "Status": 1,
        "NextRenewalCustomerGrossPrice": 1200.0
      }
    ]
  },
  "ResultMessage": "OK"
}

Step 2: Add additional seat immediately at a discounted price

If the API call is formatted as described below, it will update the customer's subscription data in the Cleverbridge platform.


Parameter

Type

Required

Example

Notes

AlignmentSettings

obj

Yes

{ "AlignToCurrentInterval": true, "GetCustomerPricePreviewOnly": false, "ExtendInterval": false }

Defines the rules applied when adding a new subscription item or updating an existing one, including interval alignment and pricing preview behavior.

ProductId

int

Yes

294835

Product ID of the subscription item being updated.

RunningNumber

int

Yes

1

Running number of the item in the subscription.
RunningNo from the response maps to the RunningNumber.

Quantity

int

Yes

2

Total number of items after the update.

SubscriptionId

str

Yes

S68841753

The unique identifier of the subscription.

UpdateAction

str

No

0

The value set does not affect transaction processing.
See the note below.

📘

Note

The UpdateAction parameter is currently used for documentation and tracking only. The value set does not affect transaction processing.

The supported values are as follows:

  • For upgrades, set the parameter to upgrade(or 1 for JSON)
  • For downgrades, set the parameter to downgrade, (or 2 for JSON)
  • For all other changes, set the parameter to update (or 0 for JSON)

JSON body

{
    "ProductId": 294835,
    "RunningNumber": 1,
    "SubscriptionId": "S68841753",
    "UpdateAction": 0,
    "Quantity": 2,
    "GenerateMail": false,
    "AlignmentSettings": {
        "AlignToCurrentInterval": true,
        "GetCustomerPricePreviewOnly": false,
        "ExtendInterval": false
    }
}

Request

curl --location 'https://rest.cleverbridge.com/subscription/updatesubscriptionitem' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Basic YOUR_BASE64_ENCODED_CREDENTIALS' \
--data '{
  "ProductId": 294835,
  "RunningNumber": 1,
  "SubscriptionId": "S68841753",
  "UpdateAction": 0,
  "Quantity": 2,
  "GenerateMail": false,
  "AlignmentSettings": {
    "AlignToCurrentInterval": true,
    "GetCustomerPricePreviewOnly": false,
    "ExtendInterval": false
  }
}'
import http.client
import json

conn = http.client.HTTPSConnection("rest.cleverbridge.com")
payload = json.dumps({
  "ProductId": 294835,
  "RunningNumber": 1,
  "SubscriptionId": "S68841753",
  "UpdateAction": 0,
  "Quantity": 2,
  "GenerateMail": False,
  "AlignmentSettings": {
    "AlignToCurrentInterval": True,
    "GetCustomerPricePreviewOnly": False,
    "ExtendInterval": False
  }
})
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Basic YOUR_BASE64_ENCODED_CREDENTIALS',
}
conn.request("POST", "/subscription/updatesubscriptionitem", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
var https = require('follow-redirects').https;
var fs = require('fs');

var options = {
  'method': 'POST',
  'hostname': 'rest.cleverbridge.com',
  'path': '/subscription/updatesubscriptionitem',
  'headers': {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Basic YOUR_BASE64_ENCODED_CREDENTIALS'

  },
  'maxRedirects': 20
};

var req = https.request(options, function (res) {
  var chunks = [];

  res.on("data", function (chunk) {
    chunks.push(chunk);
  });

  res.on("end", function (chunk) {
    var body = Buffer.concat(chunks);
    console.log(body.toString());
  });

  res.on("error", function (error) {
    console.error(error);
  });
});

var postData = JSON.stringify({
  "ProductId": 294835,
  "RunningNumber": 1,
  "SubscriptionId": "S68841753",
  "UpdateAction": 0,
  "Quantity": 2,
  "GenerateMail": false,
  "AlignmentSettings": {
    "AlignToCurrentInterval": true,
    "GetCustomerPricePreviewOnly": false,
    "ExtendInterval": false
  }
});

req.write(postData);

req.end();
Unirest.setTimeouts(0, 0);
HttpResponse<String> response = Unirest.post("https://rest.cleverbridge.com/subscription/updatesubscriptionitem")
  .header("Content-Type", "application/json")
  .header("Accept", "application/json")
  .header("Authorization", "Basic YOUR_BASE64_ENCODED_CREDENTIALS")
  .body("{\n  \"ProductId\": 294835,\n  \"RunningNumber\": 1,\n  \"SubscriptionId\": \"S68841753\",\n  \"UpdateAction\": 0,\n  \"Quantity\": 2,\n  \"GenerateMail\": false,\n  \"AlignmentSettings\": {\n    \"AlignToCurrentInterval\": true,\n    \"GetCustomerPricePreviewOnly\": false,\n    \"ExtendInterval\": false\n  }\n}")
  .asString();

Response

{
    "AlignmentCustomerGrossPrice": 540.82,
    "AlignmentCustomerNetPrice": 454.47,
    "AlignmentCustomerVatPrice": 86.35,
    "NextBillingCustomerGrossPrice": 1800.0,
    "NextBillingCustomerNetPrice": 1512.61,
    "NextBillingCustomerVatPrice": 287.39,
    "NextRenewalCustomerGrossPrice": 1800.0,
    "NextRenewalCustomerNetPrice": 1512.61,
    "NextRenewalCustomerVatPrice": 287.39,
    "PriceCurrencyId": "USD",
    "ResultMessage": "OK"
}

Diagram

flowchart LR
  classDef mainColor fill:#ffffff,color:#555555,stroke:#0A73D7,stroke-width:2px;

  A(["&nbsp;&nbsp;<br/><b>Promotional offer sent</b><br/>The customer receives an offer to buy additional seat <br/> at a discounted price&nbsp;&nbsp;<br/>&nbsp;"]):::mainColor
    --> B(["&nbsp;&nbsp;<br/><b>Customer Self-Service</b><br/><i>Get Subscription</i> endpoint to obtain and display the price of the additional seat&nbsp;&nbsp;<br/>&nbsp;"]):::mainColor
    --> C(["&nbsp;&nbsp;<br/><b>Purchase confirmation</b>><i>Update Subscription Item</i> endpoint used to apply the update&nbsp;&nbsp;<br/>&nbsp;"]):::mainColor