A practical guide for working with entitlements
Published: 2023-06-18 15:46:00

_This is part 3 out of a 3-part series about entitlements, first published on the Stigg blog, [here](https://www.stigg.io/blog-posts/entitlements-untangled-the-modern-way-to-software-monetization). If you're new to the concept of entitlements, check out part 1 first: "**Entitlements untangled. The modern way to software monetization**" yet, you can check it out [here](https://dev.to/getstigg/entitlements-untangled-the-modern-way-to-software-monetization-3fd6-temp-slug-2180622?preview=79f39159b6af843d3ac30edd4cf190b58cbeaff6cb338ade9ad93d6a16b4fda06f8f1fa29580ee3a3c69be3d1b09182ac26472b0ec944fb754bcc60b). And if you're already thinking of alternative ways to gate feature access in your application, check out part 2: "[The shortcomings of gating feature access using feature flags, authorization, or plan identifiers](https://dev.to/getstigg/how-to-gate-end-user-access-to-features-shortcomings-of-plan-identifiers-authorization-feature-flags-2pa5-temp-slug-881198?preview=26b778047e99f2317bcb2e1c0f8b9682ff9fee28519853ffde8d17fe578b58b0ef337f9d32f1fb92684edf5285b58e64845ee77a37c3071ed73e7da4)". Hope you enjoy reading it!_


Entitlements are a crucial aspect of any SaaS pricing & packaging. We’ve summarized a few tips we found crucial when working with entitlements.

### 1. Don’t nest entitlement checks
As you work with entitlements, one key principle to follow is to avoid nesting entitlement checks within your codebase. Nesting checks can lead to complex logic that is hard to follow, manage, and debug. Moreover, it can create interdependencies, where changes in one entitlement can unintentionally affect others.

Instead of nested checks, we recommend introducing a new entitlement, if possible, instead of depending on many entitlements. If that's not an option, at least you can introduce an abstraction that wraps those entitlement checks as a single function to better deal with this kind of coupling, and make it easier to change in the future. A singular check streamlines your code and makes it easier to understand and maintain.

Example of alternatives to nested entitlement checks:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vld4u76bjuptnwe8qu4l.png)

[Link to code](https://carbon.now.sh/?bg=rgba%2874%2C144%2C226%2C1%29&t=one-dark&wt=bw&l=javascript&width=760&ds=false&dsyoff=20px&dsblur=68px&wc=false&wa=false&pv=0px&ph=0px&ln=false&fl=1&fm=Fira+Code&fs=14px&lh=152%25&si=false&es=4x&wm=false&code=%252F%252F%2520try%2520to%2520avoid%2520nested%2520entitlement%2520checks%250Aif%2520%28canAccessFeature%28tenant.id%252C%2520%27feature-dashboards%27%29%29%2520%257B%250A%2520%2520if%2520%28canAccessFeature%28tenant.id%252C%2520%27feature-revenue-management%27%29%29%2520%257B%250A%2520%2520%2520%2520%252F%252F%2520grant%2520access%250A%2520%2520%257D%250A%257D%250A%250A%252F%252F%2520introduce%2520a%2520single%2520entitlement%2520instead%250Aif%2520%28canAccessFeature%28%27feature-revenue-dashboard%27%29%29%2520%257B%250A%2520%2520%252F%252F%2520grant%2520access%250A%257D%250A%250A%252F%252F%2520if%2520not%2520possible%252C%2520wrap%2520both%2520checks%2520in%2520a%2520single%2520function%250Afunction%2520canAccessRevenueDashboard%28tenantId%29%2520%257B%250A%2520%2520return%2520%28%250A%2520%2520%2520%2520canAccessFeature%28tenantId%252C%2520%27feature-dashboards%27%29%2520%2526%2526%250A%2520%2520%2520%2520canAccessFeature%28tenantId%252C%2520%27feature-revenue-management%27%29%250A%2520%2520%29%250A%257D%250A%250Aif%2520%28canAccessRevenueDashboard%28tenant.id%29%29%2520%257B%250A%2520%2520%252F%252F%2520grant%2520access%250A%257D)

### 2. Never assume new entitlements are ‘there’
Due to the dynamic nature of entitlements, and the fact that they can be moved between plans, there is a chance an entitlement won't be present at all anymore.
Never assume that there are “mandatory” entitlements to ensure the application can continue to work properly. This will make your application less fragile and less subject to errors due to miss-configuration of entitlements. 

Let’s say, you’ve added a new entitlement to a new version of your Free plan in your development environment. You can’t expect that this entitlement will be available until you’ll finish migrating all of your free customers to this new plan version. In the meantime, if the new entitlement check was already deployed - it must accommodate the fact that the entitlement is missing, or else the application will break.

### 3.  Embrace the “fail open” principle
Entitlements are a critical component of any infrastructure. It's crucial to account for potential service disruptions. The "fail open" principle states that in the event of a failure, default access permissions should grant the user as much access as possible without breaking the application invariants. This ensures that users can continue to access necessary services, even when your entitlement service encounters an issue.

### 4. Create a centralized module in the code that evaluates the entitlements
In general, it’s good practice to keep the entitlement checks at bay by introducing a shared module or a class that encapsulates the checks for different features. This type of  will make it much easier to track and change entitlement-related logic. It also helps define a more “business centric” terminology, when using entitlements in different areas of the application. 

Think about this scenario. You have an entitlement ‘seats’. Inside your application, there is a members page for your customers to invite more team members. The invite button is enabled if the number of members is below the entitlement limit. Introducing a `canInviteMembers(numOfNewMembers)` function that checks for the seats entitlement against the current usage of the entitlement can help simplify the access check logic and re-use it throughout other places in the application.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74v9vnzg2naa2nsip2oi.png)

[Link to code](https://carbon.now.sh/?bg=rgba%2874%2C144%2C226%2C1%29&t=one-dark&wt=bw&l=javascript&width=1130&ds=false&dsyoff=20px&dsblur=68px&wc=false&wa=true&pv=0px&ph=0px&ln=false&fl=1&fm=Fira+Code&fs=14px&lh=152%25&si=false&es=4x&wm=false&code=%252F%252F%2520Example%2520of%2520a%2520React%2520hook%2520encapsulating%2520entitlmement%2520checks%2520through%2520out%2520the%2520app.%250A%252F%252F%2520Assuming%2520the%2520tenant%2520%2560entitlements%2560%2520were%2520already%2520fetched%2520and%2520are%2520passed%2520to%2520this%2520hook.%250Aimport%2520%257B%2520useMemo%2520%257D%2520from%2520%27react%27%250A%250Aexport%2520const%2520useEntitlements%2520%253D%2520%28entitlements%29%2520%253D%253E%2520%257B%250A%2520%2520return%2520useMemo%28%28%29%2520%253D%253E%2520%257B%250A%2520%2520%2520%2520return%2520%257B%250A%2520%2520%2520%2520%2520%2520canAccessAdvancedDashboards%28%29%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520return%2520%21%21entitlements%255B%27advanced-dashboards%27%255D%250A%2520%2520%2520%2520%2520%2520%257D%252C%250A%2520%2520%2520%2520%2520%2520getDataRetentionDays%28%29%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520return%2520entitlements%255B%27data-retention-days%27%255D%253F.value%2520%257C%257C%25200%250A%2520%2520%2520%2520%2520%2520%257D%252C%250A%2520%2520%2520%2520%2520%2520canInviteMembers%28numOfNewMembers%29%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520const%2520entitlement%2520%253D%2520entitlements%255B%27seats%27%255D%250A%2520%2520%2520%2520%2520%2520%2520%2520if%2520%28%21entitlement%29%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520return%2520false%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520return%2520entitlement.usage%2520%252B%2520numOfNewMembers%2520%253C%253D%2520entitlement.limit%250A%2520%2520%2520%2520%2520%2520%257D%252C%250A%2520%2520%2520%2520%2520%2520%252F%252F%2520...%2520more%2520entitlement%2520related%2520logic%250A%2520%2520%2520%2520%257D%250A%2520%2520%257D%252C%2520%255Bentitlements%255D%29%253B%250A%257D)


This is just a recommendation. You’ll need to adjust it to your project’s coding standards.

### 5. Less is more
This might sound obvious, but way too often, this gets out of hand… Just like feature flags, if you don’t keep your entitlements as clean and simple as possible, you’ll end up with messy code. If an entitlement does not exist anymore, first remove the entitlement checks in all the places from the codebase, and then the corresponding entitlement.

## Building an entitlement service:
Once your product is mature enough you’ll probably need an entitlement service. 

Here are a few points that you should take into consideration before attempting to build one yourself:

### 1. Prepare for network latency and downtime
Every network call adds latency to the overall system response time. Entitlements are a critical function in the service you provide. You don’t want your customers to face long response times when trying to access a feature inside your product. Always strive to optimize your entitlement service for low latency and scale, or at least make sure you have a good caching mechanism in-place.

### ‍2. Communicate usage and limits
Especially in self-service products, your customers need to be aware of their current usage and the limits of their subscription, before they are being denied access to functionalities or service. An effective entitlement service should be able to track and communicate this information clearly to users. That can be through dashboards, a self-service customer portal, or regular in-app / email notifications.

### 3. Determine your source of truth
You’ll need a source of truth. Deciding between your billing provider and your entitlement service is a significant consideration. This decision will influence how you synchronize data between the two systems. If your entitlement service includes complex logic like complex trials, scheduled downgrades, or grandfathering, this will be more suitable as your source of truth. Conversely, if your billing system is more sophisticated, then it should be the primary data source. The key is to identify which system contains the most comprehensive and accurate representation of customer data and use it to drive your entitlement decisions.


## To wrap up
Operating in highly dynamic markets, SaaS companies have much less chances of success when compromising on  rigid pricing models  managed in the codebase. 

Entitlements are the base for a truly flexible taxonomy and speed in go to market, allowing developers to quickly build and update pricing and giving GTM teams the opportunity to experiment with pricing & packaging, without code.

We made it our mission at [Stigg](https://www.stigg.io) to solve entitlements for SaaS. Our API gives you a flexible and scalable infrastructure, including metering, built-in experiments, a bunch of snap-in widgets, and native billing integrations, out of the box, and provides the automation to orchestrate everything about your pricing & packaging. If you consider buying over building, check out our [Free plan](http://app.stigg.io/signup). You can use one of our sandboxes to see all functionalities of Stigg, even before integrating it.