More Tutorials

Getting Started with Chargebee Entitlements: A step-by-step guide

Entitlements
Features

Overview

Entitlements are used to regulate the level of access that your customers have to the various features within your system. With Entitlements, you can define specific features and link them to plans, addons, and charges. As a result, those features become available to customers who purchase those plans, addons, or charges.

Setting up entitlements helps you achieve the following objectives:

  • Ensure that your users access only the features they are authorized to use
  • Identify the features that add value to your customers and generate revenue for your business
  • Capitalize on additional revenue streams
  • Boost your revenue by encouraging upsell and cross-sell
  • Reduce customer attrition by upselling or upgrading products in accordance with their expectations
  • Prevent revenue leakage that happens via unmonitored feature entitlements. Offer limited period overrides that encourages adoption and expansion without hurting the bottom line

The purpose of this tutorial is to walk you through a sample application that integrates with Entitlements by Chargebee.

Scope

The sample app covers the following scenarios:

Prerequisites

Before starting, set up the following:

  1. A Chargebee account (sign up for a free trialif needed). If your Chargebee account was created before May 5, 2021, ensure you upgrade the site to Product Catalog 2.0.
  2. Your Chargebee test site's API key.
  3. A plan item resource created in your Chargebee test site. You can do this via Chargebee UI or API.
  4. An item_price resource for the plan. You can do this via the Chargebee UI or API.
  5. A good understanding of Java Spring Boot.

Sequence Diagram

The diagram below illustrates how the sample app interacts with the user and Chargebee. The participants titled Your Frontend and Your Backend are implemented in the app and their code is explained in the section that follows.

Subscription Entitlements
Subscription Entitlements

Implementation

Initial configuration

BACKEND

Environment.configure("your-chargebee-subdomain","your-api-key");

Create a feature

BACKEND

Create a file named SetupController.java that contains a Java class with methods to handle HTTP requests for setting up and managing Chargebee resources. Implement the createFeature method to create a feature in Chargebee using the Create a feature endpoint, passing the following parameters:

  • id: a unique and immutable identifier for the feature. It is recommended to use a human-readable value, such as capacity-planning for the Capacity Planning feature in a Project Management System software

  • name: a case-sensitive unique string that serves as the name of the feature. For example, Capacity planning

  • type: the type of feature. In the case of Capacity Planning, the feature can be toggled on or off with no intermediate states, so the type should be set to switch

  • status: set this to active so that entitlements for the feature become immediately effective upon creation

  • description: A short description of the feature, such as “helps users predict resource demands and manage resource allocation”

Result result = Feature.create()
 .id(id)
 .name(name)
 .type(Feature.Type.valueOf(featureType))
 .status(Feature.Status.ACTIVE)
 .description("Plan capacity as a feature")
 .request();

Create an item entitlement

BACKEND

Now that you have created a feature, you can create an entitlement to connect it to a plan and make it available on that plan. Since you have already created a plan in Chargebee as a prerequisite to this tutorial, you can associate the previously created feature with this plan by creating an entitlement. To create an entitlement, add the setupEntitlements method in SetupController.java. This method should call the Upsert or remove item entitlements for an item endpoint in Chargebee to create an entitlement that allows the feature to be accessed via the plan. Pass the following parameters:

  • itemId: The unique ID of the item that represents the plan

  • action: Pass the value as UPSERT indicating that entitlement needs to be created, and if already created, it needs to be updated

  • itemEntitlementValue: set the level of the entitlement for the feature on this plan. Since the feature is of type switch, set this parameter to true to enable the feature for the plan. The 0 parameter indicates the index of the entitlement being specified in the API call. Since this is the first (and only) entitlement being referred to in the API call, set this to 0

  • itemEntitlementFeatureId: This sets the feature ID associated with the entitlement. The featureId parameter is the ID of the feature that this entitlement is for

Result result = ItemEntitlement.upsertOrRemoveItemEntitlementsForItem(itemId)
 .action(Action.UPSERT)
 .itemEntitlementValue(0,"true")
 .itemEntitlementFeatureId(0,featureId)
 .request();

Sign-up your customer

FRONTEND

Create a sign-up page for your customers. Add fields for username, email address, company name, and a drop-down list for selecting a pricing plan. Submit the form to the server using a POST request to the /registration endpoint.

<form method="POST" action="${contextPath}/registration" class="form-signin">
   <h2 class="form-heading"> Register </h2>

   <div class="form-group ${error != null ? 'has-error' : ''}">
       <span>${message}</span>
       <input name="username" type="text" class="form-control" placeholder="Username"
               autofocus="true"/>
       <input name="email" type="email" class="form-control" placeholder="Email"/>
       <input name="company" type="text" class="form-control" placeholder="Company Name"/>
       <select name="itemPrice" id="plan-select" class="form-control" default = "Select a plan">
       </select>
       <span>${error}</span>
       <br>

       <button class="btn btn-lg btn-primary btn-block" type="submit"> Register</button>
   </div>
</form>

Create a customer record

BACKEND

Create a file UserController.java containing a class that defines request mappings for various HTTP requests related to user authentication and registration. Within the, create a @PostMapping handler called register() that receives data from the user registration page and processes it accordingly.

@PostMapping("/registration")
public String register(Model model, String username, String email, String itemPrice, String company) throws Exception {}

Create a new UUID to serve as the unique ID for the customer record in Chargebee.

UUID uuid = UUID.randomUUID();

Create the customer record in your app

Create a new User object with the provided form data and the generated UUID. Then save the object to the database using the userRepo object.

User user = new User();
user.setId(uuid.toString());
user.setName(username);
user.setCompany(company);
user.setCustomerEmail(email);
userRepo.save(user);

Create the customer record in Chargebee

Call Chargebee’s Create a customer endpoint passing all the customer information.

Result result = Customer.create()
 .id(uuid.toString())
 .email(email)
 .company(company)
 .request();

Create a subscription in Chargebee

BACKEND

Subscribe the customer to the selected plan using Chargebee’s Create a subscription endpoint, passing the customer ID returned in the previous API call and the item price ID. This creates a subscription resource linked to the customer resource in Chargebee

result = Subscription.createWithItems(result.customer().id())
 .subscriptionItemItemPriceId(0,itemPrice)
 .request();

Store the subscription ID with the email address

BACKEND

In your application, make sure to store a mapping between the subscription ID provided by Chargebee and a unique customer attribute, such as their email address. This will enable you to easily retrieve the details of the user's subscription during future login sessions.

UserSubscription userSubscription = new UserSubscription();
userSubscription.setEmail(email);
userSubscription.setId(result.subscription().id());
userSubscription.setCustomerId(result.subscription().customerId());
subscriptionRepository.save(userSubscription);

Set user properties in the Model object

BACKEND

After the user has successfully logged in, redirect them to the dashboard view. Prior to the redirection, set the Model object with the customer's email address and subscription ID so that they are available for use on the dashboard view. The next step will show how to use them on the dashboard.

if(userSubscription.isPresent()){
   model.addAttribute("user", userSubscription.get().getEmail());
   model.addAttribute("subscriptionId",userSubscription.get().getId());
   return "dashboard";
}

Show dashboard with feature button

FRONTEND

Create a JSP file named dashboard.jsp that contains the HTML markup and JSP tags for rendering the dashboard view of the application. It should receive two pieces of information from the application via the Spring model attributes set in the previous step. The first piece of information is the user attribute, which contains the email address of the logged-in customer. Display this in the HTML markup using the ${user} expression. The second piece of information is the subscriptionId attribute. Include this as a path variable in the URLs of the feature request forms. For example: /user/${subscriptionId}/feature. This attribute is used by the application to identify the user's subscription and to process the feature requests submitted via the forms.

<div class="cd-content-wrapper">
 <div class="text-component text-center">
   <h1>Acme Corp Project Management Software</h1>
   <div class="d-flex align-items-center justify-content-center" style="height: 100px">
     Customer Name : ${user}
   </div>
   <form class="form-center" action="/user/${subscriptionId}/feature" method="post">
     <input class="form-control" type="submit" name="requestedFeature" value="plan-capacity" aria-valuetext="Plan-Capacity">
   </form>
   <form class="form-center" action="/user/${subscriptionId}/feature" method="post">
     <input class="form-control" type="submit" name="requestedFeature" value="Higher-Plan-Feature" aria-valuetext="Higher-Plan-Feature">
   </form>
 </div>
</div> 

Evaluate subscription entitlements and grant access

FRONTEND

  1. Intercept all user requests against the user’s entitlements by registering an interceptor in WebMvcConfig.java that applies to all URL paths starting with /user/.
public void addInterceptors(InterceptorRegistry registry) {
 registry.addInterceptor(entitlementInterceptor).addPathPatterns("/user/**");
}
  1. Add a preHandle() method in the EntitlementInterceptor.java interceptor class definition to evaluate whether the user has access to the requested feature before handling the user request. Within preHandle(), use evaluateAccess() to check whether the user's subscription is entitled to the requested feature. If so, return true to proceed further and allow the actual handler for the request to be invoked. Otherwise, redirect the user to the HigherPlan.html page prompting them to upgrade their subscription plan.
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

   String requestedFeature = request.getParameter("requestedFeature");
   Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
   String subscriptionId = (String) pathVariables.get("subscriptionId");
   Optional<UserSubscription> userSubscription = subscriptionRepository.findById(subscriptionId);
   if(evaluateAccess(userSubscription.get(), requestedFeature)){
       return true;
   }else {
     response.sendRedirect("/HigherPlan.html");
     return false;
   }
}
  1. The preHandle() method calls the evaluateAccess() method, which calls the List Subscription Entitlements API. If a subscription entitlement is found for the feature requested by the user, the method returns true.
private Boolean evaluateAccess(UserSubscription userSubscription, String requestedFeature) throws Exception {
   ListResult resultList= SubscriptionEntitlement.subscriptionEntitlementsForSubscription(userSubscription.getId()).request();
   for (ListResult.Entry result: resultList) {
       if (StringUtils.equals(requestedFeature, result.subscriptionEntitlement().featureId())) {
           return true;
       }
   }
   return  false;
}
  1. Once preHandle() is successful, redirect the user to the feature page by defining a controller in BusinessLogicController.java with a method hasAccess() mapped to the user's request for the feature landing page. The hasAccess() method should return a RedirectView object constructed with the URL path /{requestedFeature}.html where {requestedFeature} is passed as a request parameter from the dashboard.
@Controller
public class BusinessLogicController {

   @PostMapping(
           path = "/user/{subscriptionId}/feature",
           consumes = {MediaType.ALL_VALUE})
   public RedirectView hasAccess(@PathVariable String subscriptionId, @Validated @RequestParam String requestedFeature)
           throws Exception {
       // sanitize input
       String url = "/"+requestedFeature+".html";
       return  new RedirectView(url);
   }
}

Next steps

This tutorial has covered the basics of setting up entitlements by Chargebee and integrating it into a sample Java Spring Boot application. You should now have a good understanding of how entitlements work and how you can use them to control access to your product features. Additionally, you can refer to our tutorial on Checking Subscription Entitlements and Providing Access.

For more information on other features and how to use them, explore the Entitlements API documentation.

Was this tutorial helpful ?
Need more help?

We're always happy to help you with any questions you might have!

support@chargebee.com