Entitlements¶
An entitlement is the resolved answer for one subscriber and one feature right now.
Entitlements are not the source of truth you edit. You edit plans, subscriptions, and overrides. Checks compute entitlements.
Resolution order¶
effective(subscriber, feature) =
if non-expired override for feature exists → override value
else if active subscription's plan grants feature → plan value
else → not entitled
| Feature kind | Not entitled | Entitled |
|---|---|---|
flag |
allowed: false, source: none |
allowed: true, source: plan \| override |
limit |
limit: 0, source: none |
limit: N \| null, source: plan \| override |
limit: null means unlimited.
Check vs list¶
| Operation | Use |
|---|---|
| Check one feature | Hot path in your API |
| List effective features | Admin UI, debugging, bootstrapping a session |
Source¶
source |
Meaning |
|---|---|
override |
Non-expired override decided it |
plan |
Active plan grant applied |
none |
No override, no plan grant |
For flags, denies from override still use source: override with allowed: false.
For limits, a plan grant of 0 is still source: plan with limit: 0 (explicit zero). Missing grant is source: none, limit: 0.
Usage (your app)¶
e10s does not know how many seats are filled. Typical pattern:
entitled = check(subscriber, "seats").limit # number | null
used = countUsersInYourDb(customer)
if (entitled !== null && used >= entitled) reject
Caching¶
Checks are the hot path. You can cache results briefly on your side; invalidate when that subscriber’s subscription or overrides change, or when the plan’s grants change.
What entitlements are not¶
- Not a permission system for rows inside your app
- Not usage remaining (“3 seats left”) — that is
entitled − usedin your app - Not metered billing or overage