Entitlements
Resources a customer on a plan is allowed to use.
Entitlements live inside plan definitions, identified by a string ID. An entitlement without a limit is a boolean flag — present means the customer has access. An entitlement with a limit is metered.
Entitlement schema
entitlements:
<entitlement-id>:
description: string # Optional. Appears in event payloads.
hidden: bool # Exclude from public serialization. Default: false.
scope: string # Optional. Customer type scope (e.g. 'org').
limit: # Optional. Omit for a boolean access entitlement.
<Limit fields>
description
Human-readable description. Included in event payloads (meter-limit, meter-overage, meter-changed) and in the customer object. Useful for support tooling and dashboards.
hidden
If true, the entitlement is excluded from public policy serialization. Use for internal metering that customers shouldn't see.
scope
Ties the entitlement to a customer type. When set, enforcement operations for this entitlement look through the customer's refs to find a customer of the matching type, and operate against that customer's meter instead.
The canonical use case is org-scoped entitlements — a seats entitlement with scope: org means all users who ref the same org draw from the org's shared seat pool, not their individual meters.
seats:
scope: org
limit:
credit: seat
mode: hard
value: 10
increment: 1
Any member of the org calling policy.increment('user_123', 'seats') draws from the org's pool.
Limit schema
limit:
credit: string # Required. Credit ID for this limit.
mode: string # 'hard' | 'soft' | 'observe'. Default: 'hard'.
value: float | string # Maximum value. Supports unit strings (e.g. '2GiB'). Default: 0.
increment: float | string # Amount per increment()/decrement(). Default: 1.
minimum: float | string # Optional floor value for decrement().
resets: bool # Does this meter reset? Default: false.
reset_inc: duration # Reset interval. Default: 30days.
override_expires_on: ms # Expiry for customer overrides only.
credit
The credit ID this limit is denominated in. Must reference a credit defined in policy.credits. Required.
mode
Controls what happens when consumption reaches the limit value.
| Mode | Behavior |
|---|---|
hard | Blocks the operation. allow() returns false. Fires meter-limit. No overage unless covered by a grant. Default. |
soft | Allows the operation. Fires meter-overage. Limitr draws from applicable grants first before firing the event. |
observe | Never blocks. Meters indefinitely. No enforcement. Useful for tracking usage without restricting it. |
value
The enforced maximum. When a customer's meter reaches this value, hard mode blocks and soft mode fires overage. Supports raw floats or unit strings when the credit has stof_units defined.
value: 500000 # raw float
value: '2GiB' # unit string — converted to the credit's stof_units
value: 0 # soft limit of 0: every increment fires meter-overage immediately
increment
The amount consumed or released per increment() / decrement() call. Defaults to 1. Supports unit strings.
increment: 1 # one seat per call
increment: '100MB' # 100MB per upload slot
minimum
An optional floor value. decrement() will not reduce the meter below this value.
resets and reset_inc
Whether and how often the meter resets. When resets: true, the meter is zeroed at each reset_inc interval starting from when the customer was created.
resets: true
reset_inc: 1day # resets daily
reset_inc: 30days # resets monthly (default when reset_inc is omitted)
Valid time units: ms, s, min, hr, day, days.
Resets are not calendar-aware by default. They run from the customer's creation timestamp, not from the start of a calendar month or day.
Boolean entitlements
An entitlement with no limit field is a boolean flag. allow() or check() against it returns true if the entitlement exists on the plan, false if it doesn't.
entitlements:
pdf_export:
description: Access to PDF export feature
const canExport = await policy.check('user_123', 'pdf_export');
if (!canExport) return { error: 'Upgrade to export PDFs' };
Customer overrides
An override replaces the limit for a specific customer without changing the plan. Any limit field can be overridden. Overrides can have an expiry, after which the customer reverts to their plan's limit.
// Give enterprise_org 500 seats instead of the plan default
await policy.createCustomerOverride('enterprise_org', 'seats', 500);
// Override with an expiry
await policy.createCustomerOverride(
'user_123',
'chat_input',
2000000,
Date.now() + 30 * 24 * 60 * 60 * 1000 // expires in 30 days
);
// Remove an override — customer reverts to plan limit
await policy.removeCustomerOverride('user_123', 'chat_input');
Full signature:
policy.createCustomerOverride(
id: string, // customer ID
entitlement: string, // entitlement name
value?: string | number, // limit value
expires_on?: number, // expiry timestamp (ms)
credit?: string, // credit ID (if changing the credit)
mode?: string, // 'hard' | 'soft' | 'observe'
increment?: number | string,
resets?: boolean,
reset_inc?: number | string
): Promise<string | null> // returns override node ID, or null on failure
SDK
policy.entitlement()
Returns the entitlement record for a given plan ID or customer ID and entitlement name. Includes the resolved limit with any customer override applied.
const ent = await policy.entitlement('user_123', 'chat_input');
// { description, limit: { credit, mode, value, resets, reset_inc, ... } }
policy.limit()
Returns the enforced limit value for a customer's entitlement. Includes credit grant balances in the effective limit when grants is true (default). Returns null if no limit is defined.
const limit = await policy.limit('user_123', 'chat_input'); // with grants
const limit = await policy.limit('user_123', 'chat_input', false); // without grants
policy.createCustomerOverride()
See Customer overrides above.
policy.removeCustomerOverride()
Removes a customer override. The customer reverts to their plan's limit.
await policy.removeCustomerOverride('user_123', 'chat_input');