Skip to content

Keep plan rules out of your code

Your app should check a customer’s access with one call. Entitler works out the answer from the plan version each customer holds, their add-ons, grants and usage.

Early access. We invite teams in small groups.

Explore the example
Example preview
support-contact.ts
Removed: if (user.plan === "pro" || user.plan === "team") {Added: const { entitlement } = await check(user.id, "priority_support")Added: if (entitlement?.entitled) {  showPriorityContact()}
Entitlements.CheckFeature: cus_42, priority_support
{
  "served": { "track": { "id": "t7Rw2NcQ5vLp8ZsKx3MhYd1", "name": "All customers" }, … },
  "entitlement": {
    "featureKey": "priority_support",
    "kind": "ENTITLED_FEATURE_KIND_SWITCH",
    "value": { "switch": true },
    "entitled": true,
    "sources": [
      { "addOn": { "planKey": "support_standard", "planName": "Standard support", … } }
    ],
    …
  },
  …
}

The plan-name check missed customers with a support add-on. The feature check includes them.

One check, with the customer’s terms behind it

Start with a simple check. Then change a plan in a change and decide whether an existing customer keeps their terms or moves to the new version. This example runs in Staging, a test environment with an All customers track running a release, as Production’s does.

Your server asks about a feature
const entitlements = createClient(Entitlements, transport)
const { entitlement } = await entitlements.checkFeature(
  { customer: { customer: { case: 'externalId', value: 'cus_42' } }, featureKey: 'priority_support' },
  { headers: { Authorization: 'Bearer YOUR_SERVER_KEY' } },
)

OK · Shortened answer

{ "entitled": true, "value": { "switch": true },
  "sources": [{ "addOn": { "planName": "Standard support", … } }] }

The customer can contact priority support through their Standard support add-on.

Step 1 of 5: Find the plan checks

Step 1 of 5: Find the plan checks

Three apps use plan names to decide access to priority support.

const canUsePrioritySupport =
  user.plan === "pro" || user.plan === "team"

if (canUsePrioritySupport) showPriorityContact()
  • Customers this check misses
  • Pro basic customers with the Standard support or Premium support add-on
  • Customers with an active priority support grant
  • Future plans that include priority support

Customer entitlement, usage and pricing API

Call https://api.entitler.app over gRPC-Web with a key or a customer token as Authorization: Bearer. Name a customer by the ID you gave Entitler, or as me for the customer that a customer token or an Entitler-Identity-Token names.

Keys and environments

Each project has test and live environments, such as Development, Staging and Production, and each holds its own customers, usage and API keys. A key holds the permissions you choose when you create it and is secret or publishable: a browser is answered only with a publishable key, from an origin you list on it.

More jobs the API takes off your hands

Use the same API to support pricing pages, plan changes, grants and upgrades.

  • Load everything at sign-in

    Your app needs to know about a dozen features as soon as someone signs in. Call Entitlements.ListEntitlements with the customer’s ID, or with customer.me from an app holding a customer token or identity token, to read every entitlement with its value and sources. Metered features also carry a meter with used, held, remaining and resetsAt.

  • Count customer usage

    Stop AI credits at the allowance without counting retried requests twice. Before the AI call, call Usage.ReportUsage from your server with featureKey ai_credits, amount 1, the gate mode and an idempotency key. A gated report for the current period past the allowance is refused and records nothing, even when requests arrive together. Use the observe mode instead to record the use and show how far over the allowance it went. If the AI call fails after the report is recorded, cancel it with Usage.CancelReport and the report’s usageId. If the report itself fails, retry it with the same idempotency key. A repeat under the same key comes back as a duplicate and is not counted again.

  • Show prices on your pricing page

    Your pricing page should list the plans on sale, with prices, without a deploy for each change. Call Pricing.GetPricing with a publishable key that holds catalogue:read. The answer lists the plans on sale on the default track, each billing period’s price on every channel and whether it can be bought there, so a plan with no listing on a channel can show as Coming soon.

  • Give beta customers a newer release

    Some customers have agreed to try the next release before everyone else. From your server, call CustomerTracks.AssignTrack with the Beta track’s ID. Their checks and Pricing.GetCustomerPricing then answer from the release Beta runs, and their purchases go through the environment’s connections at the prices listed on Beta. Name no track to return them to All customers.

  • A grant from support

    Support gives a customer on Free two weeks of Export to PDF. The same check includes active grants automatically. Once the grant expires, it no longer contributes to access.

    Explore grants
  • Changing billing provider

    You have to move from one billing provider to another. Keep the same Entitler feature checks while updating your billing integration separately.

    More on changing billing provider

Questions engineers ask

Any language with a gRPC-Web client. Entitler’s API is gRPC-Web, defined in Protocol Buffers, at https://api.entitler.app. Any language with a gRPC-Web client can call it. The examples here use a TypeScript client generated for Connect, with the key sent as Authorization: Bearer.

Try your plans in Entitler

Start with sample plans and customers. Then try a change you expect to make, such as a new tier, a usage allowance or an exception for an early customer. Request an invite to try it with your team.

Early access. We invite teams in small groups.