Entitlements
Entitlement Types
BOOLEAN, NUMBER, NUMBER_AI_CREDIT, and CONFIG — the value shape of each type, what a NUMBER carries on the catalog, and what its grant carries on the License.
Overview
Every entitlement has a type, set at creation and immutable afterwards. The type fixes two things: the shape of the value a License grants, and whether the entitlement is measured at all. Only the NUMBER family is metered; a BOOLEAN or CONFIG value is read by your product, never reported against.
Examples use $KAITEN_API and $KAITEN_TOKEN as set up in the quickstart, and the Kaiten Sushi Shop catalog. On a stack seeded with the demo data these entitlements and their grants already exist with the definitions shown — sending one again returns 409 Conflict; read them instead. Slugs are kebab-case: the API refuses an underscore in a slug.
BOOLEAN
Included, or not. Used for feature gates that a flag rule or your product reads.
Grant value:
{ "type": "boolean", "value": true }Kaiten Sushi Shop: delivery-tracking — false on Starter, true on every version of Premium, and the one entitlement that differs between the two versions of Standard: false on standard, the version the family serves, true on standard-v2. The delivery-tracking-enabled flag reads the grant, so the feature follows the License version without listing a single customer.
curl -X POST "$KAITEN_API/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Delivery Tracking",
"slug": "delivery-tracking",
"description": "Real-time delivery tracking for end customers.",
"type": "BOOLEAN",
"groupSlugs": ["delivery"]
}'curl -i -X POST "$KAITEN_API/licenses/premium-v2/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entitlementSlug": "delivery-tracking",
"value": { "type": "boolean", "value": true }
}'A grant is written on one version of a License, addressed by that version's slug — premium-v2 is the version the Premium family serves.
A BOOLEAN entitlement carries no aggregation method, no warning threshold, and no reset period — the API refuses them on this type. Its grant carries no overage allowance either.
NUMBER
A measurable quota. The entitlement declares how the quota is measured; each grant declares how much a License gives and how strictly that number is enforced.
Grant value:
{ "type": "number", "value": 20 }-1 is the unlimited sentinel — a grant of -1 is never exceeded.
Kaiten Sushi Shop: monthly-orders (a SUM counter that resets every calendar month), menu-items, delivery-drivers, and locations (three LATEST gauges — each report states the current count).
curl -X POST "$KAITEN_API/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Monthly Orders",
"slug": "monthly-orders",
"description": "Orders a restaurant can process per month.",
"type": "NUMBER",
"aggregationMethod": "SUM",
"resetPeriod": "MONTH",
"resetAnchor": "CALENDAR",
"groupSlugs": ["restaurant-operations"],
"icon": "lucide:shopping-cart",
"unitSingular": "order",
"unitPlural": "orders",
"userFacing": true,
"displayOrder": 2
}'The seeded catalog presents every entitlement to customers — an icon, a display order, and unit labels on the NUMBER ones — and sets no warning threshold; the tables below list what an entitlement can also carry.
curl -i -X POST "$KAITEN_API/licenses/starter/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entitlementSlug": "monthly-orders",
"value": { "type": "number", "value": 20 },
"limitCapExceededOveragePercent": 0
}'What the entitlement carries — the measurement, identical for every License:
| Property | Required | Meaning |
|---|---|---|
aggregationMethod | Yes — defaults to SUM when omitted | How each append folds into the total: SUM, COUNT, AVERAGE, MAX, MIN, LATEST. Immutable once set. |
warningThresholdPercent | No — 0 disables it | Percentage of the granted value at which INSTANCE_ENTITLEMENT_USAGE_WARNING_THRESHOLD_REACHED fires, once per crossing |
resetPeriod / resetAnchor | No — unset means a lifetime counter | HOUR, DAY, WEEK, MONTH, or YEAR, anchored on the UTC CALENDAR or on the instance's LICENSE_START. Set together; immutable once set; not allowed with LATEST. |
unitSingular / unitPlural | No | Base unit labels, set together |
saleUnitSingular / saleUnitPlural / saleUnitFactor | No | The unit the quota is sold in, when it differs — the trio is set together and requires the base units |
What the grant carries — the contract, per License:
| Property | Required | Meaning |
|---|---|---|
value | Yes | { "type": "number", "value": <n> }; -1 for unlimited |
limitCapExceededOveragePercent | No — defaults to -1 for an unlimited value, 0 otherwise | -1 when the value is -1; 0 for a hard cap; a positive percentage for a soft limit, accepted up to value + value × percent / 100 |
The seeded grants read the same entitlement three ways: Starter caps monthly-orders at 20 with 0 (hard cap), Standard grants 100 with 10, Premium 1,000 with 20. Usage & Thresholds carries the arithmetic; Metering the aggregation methods and the windows.
NUMBER_AI_CREDIT
A NUMBER whose unit is AI credits. It is a distinct type so that your catalog and your pricing pages can tell credits apart from other quotas — and so that the AI Control Plane Coming soon can build on it — but it is created, granted, measured, and enforced under exactly the NUMBER rules: an aggregation method is mandatory, the grant carries limitCapExceededOveragePercent, the same three values mean the same three things, and a report above the maximum allowed usage is refused the same way.
curl -X POST "$KAITEN_API/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Menu Copywriting Credits",
"slug": "menu-copy-credits",
"description": "AI credits for generated dish descriptions.",
"type": "NUMBER_AI_CREDIT",
"aggregationMethod": "SUM",
"resetPeriod": "MONTH",
"resetAnchor": "CALENDAR"
}'Kaiten Sushi Shop's seeded catalog has no AI-credit entitlement; the one above is an addition you can make next to it.
CONFIG
A structured value — a JSON object your product reads as-is. Used for settings that vary by License and are not a number or a switch.
Grant value:
{ "type": "object", "value": { "tier": "priority", "channels": ["email", "slack"], "response_sla_hours": 4 } }Kaiten Sushi Shop: support-tier — the support channels and response commitment of each License (community, standard, priority), read by the product's help center.
curl -X POST "$KAITEN_API/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Support Tier",
"slug": "support-tier",
"description": "Support channel and response commitment for the restaurant.",
"type": "CONFIG",
"groupSlugs": ["restaurant-operations"]
}'curl -i -X POST "$KAITEN_API/licenses/premium-v2/entitlements" \
-H "Authorization: Bearer $KAITEN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entitlementSlug": "support-tier",
"value": {
"type": "object",
"value": { "tier": "priority", "channels": ["email", "slack"], "response_sla_hours": 4 }
}
}'The grant's type discriminator for a CONFIG entitlement is object, not config. Like BOOLEAN, a CONFIG entitlement carries no measurement fields and its grant no overage allowance.
Comparison
BOOLEAN | NUMBER / NUMBER_AI_CREDIT | CONFIG | |
|---|---|---|---|
| Grant value | {"type": "boolean", …} | {"type": "number", …} — -1 unlimited | {"type": "object", …} |
| Aggregation method | Forbidden | Mandatory | Forbidden |
| Warning threshold, reset period | Forbidden | Optional | Forbidden |
| Overage allowance on the grant | None | -1 / 0 / > 0 | None |
| Usage reporting | Refused | Yes | Refused |
| Crossing events | No | Yes | No |
| Typical use | Feature gates | Quotas and limits | Structured settings |
Entitlement properties
The body of POST /entitlements; PUT /entitlements/{slug} takes the same fields minus slug, and rejects a changed type, aggregationMethod, resetPeriod, or resetAnchor.
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name — Monthly Orders |
description | string | Yes | What the right means |
type | enum | Always set it | BOOLEAN, NUMBER, NUMBER_AI_CREDIT, or CONFIG; immutable — the spec declares no default |
slug | string | No | 2–100 characters, ^[a-z0-9][a-z0-9-]*[a-z0-9]$, unique per organization; derived from the name with a random suffix when omitted — pass an explicit slug when you need a predictable one |
aggregationMethod | enum | NUMBER family only | SUM (default), COUNT, AVERAGE, MAX, MIN, LATEST; immutable |
warningThresholdPercent | integer | No | 0–100; 0 disables the warning |
resetPeriod | enum | No | HOUR, DAY, WEEK, MONTH, YEAR; unset means a lifetime counter; immutable |
resetAnchor | enum | With resetPeriod | CALENDAR (default) or LICENSE_START; immutable |
unitSingular / unitPlural | string | No | Base unit labels, NUMBER family only, set together |
saleUnitSingular / saleUnitPlural / saleUnitFactor | string / number | No | Sale unit trio, set together; saleUnitFactor > 0 |
userFacing | boolean | No | Shown in customer-facing components; defaults to false |
displayOrder | integer | No | Ascending sort order in customer-facing components; defaults to 0 |
icon | string | No | provider:name token — lucide:shopping-cart |
groupSlugs | string[] | No | Groups to add the entitlement to |
Exact reference — columns and CHECK constraints: the entitlement table.
Overview
The catalog of typed rights, the grant that carries each License's value and its enforcement, and the usage measured against it — the deep-dive behind Licenses & Entitlements and Usage & Metering.
Entitlement Groups
Named sets of entitlements — how to create a group, add and remove members, and read the aggregated usage of a group for one instance.