Entitlements API
Lookup material for the entitlements endpoints in Nirmata AIControls. One shows what the install may use, to every signed-in role. Another adds how much of each limit is used, to admins and viewers. A third lets an admin select the enforcement mode.
Endpoints
The endpoints return JSON. The first two use GET; the enforcement endpoint takes GET and PUT.
| Endpoint | Who can call it | Returns |
|---|---|---|
GET /api/v1/entitlements | Admin, viewer, and developer tokens | Plan, add-ons, feature states, and limit values. No usage and no customer name. |
GET /api/v1/entitlements/usage | Admin and viewer tokens | Each limit with its current count, plus seat and team counts and monthly Judge and Analyst calls. |
GET, PUT /api/v1/admin/entitlements/enforcement | Admin tokens | The enforcement mode status; PUT selects the mode. See Enforcement mode. |
A developer token receives 403 from the usage endpoint, and viewer and developer tokens receive 403 from the enforcement endpoint. A request with missing or invalid credentials receives 401 from all of them.
The admin-only /api/v1/admin/license endpoint adds resolvedPlan, source, addons (with the licensed agent count) and limits to the licence status. It also adds licenceRejection, the full reason a stored licence was refused, which can name tenant or cluster ids and so is not returned elsewhere.
Entitlements response
| Field | Description |
|---|---|
catalogueRevision | The plan catalogue revision this build uses. |
enforcementMode | compat or catalogue. In compat, features[].enabled follows the gates that apply today. |
plan | free, team, business, or enterprise. |
trial | true when the licence is a trial. |
source | Where the plan came from: licence, none, or legacy_ui_tier. |
expiredPlan | The plan of an expired licence, so a page can say "Business licence expired, running on Free". Empty otherwise. |
nextChangeAt | RFC 3339 time at which the response next changes on its own: a licence or add-on expiry, the end of a grace period, or the start of the next monthly window. Empty when nothing is time-bound. |
addons | Active add-ons: id, expiresAt (empty when it lasts as long as the licence), and inGrace. |
features | A map from feature key to its state. See Feature state. |
limits | A map from limit name to its value. See Limit value. |
Feature state
| Field | Description |
|---|---|
enabled | Whether the feature is available. |
requiredPlan | The lowest plan that includes the feature. Absent when none does. |
requiredAddon | The add-on that includes the feature. Absent when none does. |
reason | Why the feature is on or off: plan, addon, addon_expired, addon_ineligible, exception, deployment_profile, roadmap, blocked, legacy, or compat (compat mode, no legacy gate covers the key so it is available). |
title | The display name of the feature. |
Limit value
The limits map is keyed by limit name: gateway_identities, gateway_requests, seats, teams, retention_raw_days, retention_trend_days, upstreams, full_capture_sessions_per_seat, and workload_agents. See Limits for each plan's values.
| Field | Description |
|---|---|
value | The cap. null when the limit is unlimited or blocked, never 0. |
unlimited | true when nothing is capped. |
blocked | true when everything is refused, for example a hosted tenant with no licence. |
atLimit | What happens at the limit. block_new: new additions are refused. hard_402: requests are refused until the month resets. billing_review: nothing is refused and the install is flagged. clamp: retention is capped at the value. lock_range: history beyond the window is not returned. degrade: one optional behavior turns off. |
window | month when the count resets each UTC calendar month, otherwise none. |
Usage response
| Field | Description |
|---|---|
limits | The limit values above, plus the fields in Limit usage. |
month | The UTC month the monthly counts cover, as YYYY-MM. |
seats, teams | Current counts. |
judgeCallsMonth, analystCallsMonth | Judge and Analyst calls this month. |
licenceRejection | Present when the stored licence was refused: unknown_plan, upgrade_required, or invalid. The code only. The full reason is on the admin licence endpoint. |
A count that cannot be read is null, not 0.
Each limit is counted as Plan limits describes. Seats and monthly counts use the UTC calendar month.
Limit usage
In the usage response, atLimit is a boolean and the catalogue behaviour moves to behavior.
| Field | Description |
|---|---|
current | The current count. null when the limit has no count, such as retention, or the count could not be read. |
warn | true at or above the warning threshold. |
atLimit | true when current has reached value. Always false for billing_review limits: the condition is reported in billingReview. |
overGrace | true when current has reached the value plus the grace allowance. |
billingReview | true when a billing_review limit is exceeded. Nothing is refused. |
behavior | The behaviour at the limit, as atLimit on the entitlements endpoint. |
capacity | The count allowed when the limit scales with seats, as full-capture sessions do. null otherwise. |
resetsAt | RFC 3339 start of the next window, for monthly limits. |
Trend window
When a plan's trend retention is shorter than the range a chart asks for, the cost dashboard and productivity overview return rows inside the window only, plus truncatedTo, the start of the window. On the cost dashboard it is an RFC 3339 string; on the productivity overview it is Unix seconds. A chart can show everything before it as locked. The response is 200, not 402. In compat mode no window applies and truncatedTo is absent.
Enforcement mode
enforcementMode is the mode this replica applies. It is compat by default. In compat, gates and limits behave as in earlier releases, decided from the legacy ui.tier and proxy.mode settings. The catalogue-only limits (seats, teams, workload agents, retention caps and the full-capture allowance) do not apply. The Free-tier caps (5 identities for the life of the install, 1,000 requests a month), trial quotas and the 2-upstream limit still do, and an Enterprise license's monthly identity and request values still flag billing review. The limits values still report the plan's catalogue values.
In catalogue, features, limits and the trend window follow the resolved plan and add-ons, and a missing feature or a refusing limit returns 402. An Enterprise license enables every feature.
An admin selects the mode with PUT /api/v1/admin/entitlements/enforcement and the body {"mode": "catalogue"} or {"mode": "compat"}; viewers and developers receive 403. GET on the same path returns the status:
| Field | Description |
|---|---|
selected | The mode an admin selected. |
applied | The mode this replica enforces. |
implements | The highest mode this version supports. |
waitingReplicas | Running replicas that do not support the selected mode yet. |
message | Why a selection has not applied yet, when it has not. |
catalogue applies within two minutes of being selected, once every running replica supports it. compat applies at once. See Turn on plan-based enforcement.
The 402 response
A request that needs a feature the plan doesn't include, or that would create something past a refusing limit, returns 402. Limits whose behavior is billing_review, clamp, lock_range or degrade don't refuse requests, so reaching them returns no 402.
{
"error": "Shadow MCP quarantine is on Business",
"upgrade": true,
"feature": "shadow_mcp_quarantine",
"required": "business",
"addon": null,
"limit": null
}
For a limit, feature is null and limit is {"name": "teams", "value": 3, "current": 3}. The body never includes the customer name or licence dates.