Logo

Entitlement

What is an Entitlement?

Entitlements are used to control access to different features, they make it possible to implement complex pricing scenarios such as monthly quotas, prepaid billing, and per-customer pricing. Let's take a look at the same example pricing page we used when discussing Features:

FeaturePlan 1Plan 2
Feature 1: GPT Tokens10,000 /m1,000,000 /m
Feature 2: Available Modelsgpt-3gpt-3, gpt-4
Feature 3: SAML SSO Auth-Yes

When your customer subscribes to a plan you need a way to track what features they can use based on the plan they have. This is where entitlements come in. You can think of each entitlement as a cell in that pricing page for one of your customers: it defines what features they can use and under what conditions.

Do it yourself!

Check out the Get Started guide to see how to create your first entitlement using the OpenMeter SDK.

You can only entitle a subject to a feature once, this is enforced by the feature key. If you want to create a new entitlement for the same featureKey, you have to delete the previous one first. This would typically happen when a customer upgrades or downgrades their plan, or when you want to archive a feature and replace it with a new one.

import { OpenMeter } from '@openmeter/sdk';
 
// Connect to locally running OpenMeter instance
const openmeter = new OpenMeter({
  baseUrl: 'http://127.0.0.1:8888',
});
 
// Create entitlement for customer-1 to use SAML SSO
await openmeter.subjects.createEntitlement('customer-1', {
  type: 'boolean',
  featureKey: 'saml_sso',
});
 
await openmeter.subjects.createEntitlement('customer-1', {
  type: 'boolean',
  featureKey: 'saml_sso',
});
// => Error: Entitlement already exists for the feature key 'saml_sso' for subject 'customer-1'

Once the entitlements are configured, you can check if a subject has access to a feature by querying the OpenMeter API. The response has a mandatory hasAccess field which you can use to enforce access control in your application.

// Verify SAML SSO access for customer-1
const { hasAccess } = await openmeter.subjects.getEntitlementValue(
  'customer-1',
  'saml_sso',
);
// => { hasAccess: true }
Migrating entitlements

If you migrate a customer from one plan to another, you need to delete the old entitlements and create new ones for the new plan. This could potentially create a window where the customer loses access to that feature. To avoid this, you can use the time parameter of the value API to query access for an exact point in time instead of always querying the latest value. We'll be releasing a dedicated migration feature in the near future to help with this.

Entitlement Types

OpenMeter has three different types of entitlements at your disposal to control access to your features:

TypeDescription
MeteredAllows granting usage based access via limits and balance calculation, as you would need for the Feature 1 example.
StaticDescribes a customer or plan specific configuration for a feature, like what models they have access to in the Feature 2 example.
BooleanRepresents true or false access to a feature, as you would need for the Feature 3 example.

The different types have specific properties and behaviors unique to their use case which we'll cover in the following sections.

Metered Entitlements

Metered entitlements are used to control access to features in cases where you want to impose usage limits on the customers. This is useful for example when the underlying resources are expensive, as is the case for most AI products. Metered entitlements leverage the usage information collected by OpenMeter and give you the ability to do real time usage enforcement as well as historical queries and access checks.

// Creating a metered entitlement with the SDK
const entitlement = await openmeter.subjects.createEntitlement('customer-1', {
  type: 'metered',
  featureKey: 'gpt_4_tokens',
  usagePeriod: {
    interval: 'MONTH',
  },
  isSoftLimit: false,
});
 
// Check the current value of the entitlement
const value = await openmeter.subjects.getEntitlementValue(
  'customer-1',
  'gpt_4_tokens',
);
const {
  hasAccess, // boolean, whether the customer has access to the feature
  balance, // the remaining balance of the entitlement
  usage, // the feature usage in the current period
  overage, // the amount of usage over the limit
} = value;

Metered entitlements have a required usagePeriod setting which defines the interval over which the usage is calculated. This can be a day, week, month, etc... but in most cases it should match with the billing cycle of your customers. The start the period is marked by a reset. At reset, a new marker is set since which usage is queried and aggregated, and the grants belonging to the entitlement are rolled over (check the Grant docs for details on how rollover works).

OpenMeter automatically executes the reset when a new usage period starts (based on the entitlement configuration) but you have the option to manually do a reset at any time after the lastReset. When doing a manual reset, you have the option to update the usagePeriod's anchor to the current reset time. This is useful for instance if the billing cycle of your customer changes and you want to align the usage period with the new cycle.

const resp = await openmeter.subjects.resetEntitlementUsage(
  'customer-1',
  'gpt_4_tokens',
  {
    // effectiveAt: optional, can be any past time since the last reset took place, defaults to now
    retainAnchor: true, // if set to false, the anchor will be updated to the reset time
  },
);

UsagePeriod is always mandated for entitlements (partly due to data retention limitations), but in some cases you might want to work with a continous running balance, where overage is not forgiven at the end of the usage period. To support these cases, you can set the preserveOverageAtReset field of an entitlement which sets the default behavior of managing overage accross usage periods. If set to true, the overage accumulated in the previous period gets deducted from the starting balance of the new period. You can also override this behavior for manual reset operations via the preserveOverage field.

const resp = await openmeter.subjects.resetEntitlementUsage(
  'customer-1',
  'gpt_4_tokens',
  {
    preserveOverage: true, // if set to true, the overage will be deducted from the starting balance
  },
);
Reset frequency

You can only reset the usage of an entitlement once per minute. If you try to reset twice for the same minute, the second request will return an error. This limit is derived from our historical granularity settings.

Alongside the real time access checks, you can also query the historical balance of a metered entitlement accross usage periods (respecting data retention). This lets you gain a deeper understanding of how your customers are utilizing their subscriptions, and its also useful for auditing purposes and customer support use cases. The history API returns a burnDownHistory and a windowedHistory with grant level information on what happened to the entitlement balance.

const {
  windowedHistory, // windowed history with usage data and balance information
  burnDownHistory, // continous history between priority changes and reset events
} = await openmeter.subjects.getEntitlementHistory(
  'customer-1',
  'gpt_4_tokens',
  {
    windowSize: 'DAY',
  },
);

For performance reasons usage data is pre-aggregated and stored in minute sized chunks. This means that historical queries are limited to a one minute granularity, but the current values are always real time. Actions like resets and granting can happen retroactively (you can specify a reset time in the past, and you can issue grants that take effect in the past). Because of the pre-aggregation, these actions are also limited to minute granularity.

Grant additional usage

Use the Grant API to grant additional usage to a customer and to define more complex balance based access rules.

Static Entitlements

Static entitlements let you define customer or plan specific configuration for a given feature. For example, you may only give freemium users access to a subset of AI models (as in Feature 2 example): with static entitlements, you can specify which models the customer can use based on their tier.

// Give access to customer-1 to use GPT-3 and GPT-4 models
const entitlement = await openmeter.subjects.createEntitlement('customer-1', {
  type: 'static',
  featureKey: 'gpt_models',
  config: JSON.stringify({ enabledModels: ['gpt-3', 'gpt-4'] }),
});

The configuration you pass has to be a JSON parsable string in an object format. This configuration is returned in the value response, making it easy to do dynamic enforcement in your application.

const value = await openmeter.subjects.getEntitlementValue(
  'customer-1',
  'gpt_models',
);
const {
  hasAccess, // boolean, whether the customer has access to the feature
  config, // { enabledModels: ['gpt-3', 'gpt-4'] }
} = value;

Boolean

In cases where you don't need to set up usage limits or configure customer level settings you can use boolean entitlements. These are simple true or false access grants to a feature. For example, you can use boolean entitlements to give a customer access to a feature like SAML SSO (as in Feature 3 example).

// Give access to customer-1 to use SAML SSO
const entitlement = await openmeter.subjects.createEntitlement('customer-1', {
  type: 'boolean',
  featureKey: 'saml_sso',
});
Try in OpenMeter Cloud

Try OpenMeter Cloud for working with entitlements:

Dashboard