5.5.2.10 Entitlements
The Entitlements domain of farm. What each Organization has (an entitlement to a feature, a model or a plan, with its limits) and how much of a metered feature it used. Staff grant and revoke; Organization users read their own; the AI gateway reserves and settles usage through the gRPC service of this domain. A domain of farm since D2 (2026-10-30): every product reads its entitlements from here. A domain of farm since D2 (2026-10-30): every product reads its entitlements from here. It is one API, with its own contract and its own version.
5.5.2.10.1 Versions¶
| Version | Status | Prod URL | Contract |
|---|---|---|---|
v1 |
Proposed | https://farm.moonitoring.com/entitlements/v1 |
entitlements/v1/openapi.yaml |
The resources follow the data model. Adds the Feature view, built from the catalogs the systems publish, and UsageSummary, which puts a period's usage next to the limit that applies.
5.5.2.10.2 Operations¶
Every operation names who calls it and the capability it checks (x-moonitoring-audience, x-moonitoring-capability in the contract); every capability is in the catalog of the data model (req 1002, 1006). Lists are paged by cursor, writes that create something carry an Idempotency-Key, errors are Problem Details.
| Operation | Request | Who | Capability |
|---|---|---|---|
| List features | GET /features |
Organization users, staff or clients | none: any member of the Organization |
| List an Organization's entitlements | GET /organizations/{organization_id}/entitlements |
Organization users, staff or clients | none: any member of the Organization or farm.entitlements.manage |
| Grant an entitlement | POST /organizations/{organization_id}/entitlements |
Staff | farm.entitlements.manage |
| List entitlements | GET /entitlements |
Staff | farm.entitlements.manage |
| Read an entitlement | GET /entitlements/{entitlement_id} |
Organization users, staff or clients | none: any member of the Organization or farm.entitlements.manage |
| Change an entitlement | PATCH /entitlements/{entitlement_id} |
Staff | farm.entitlements.manage |
| Revoke an entitlement | POST /entitlements/{entitlement_id}/revoke |
Staff | farm.entitlements.manage |
| Read an Organization's usage | GET /organizations/{organization_id}/usage |
Organization users, staff or clients | none: any member of the Organization or farm.entitlements.manage |
| Read a staff member's usage | GET /moonitoring-users/{user_id}/usage |
Staff | farm.entitlements.manage |
5.5.2.10.3 gRPC¶
ai-gateway reserves usage before every model call and settles it after, in one statement each; every product checks a feature when its cache is cold and streams the snapshot at start-up.
| Service | RPC | Callers |
|---|---|---|
EntitlementsService |
Check |
ai-gateway, moochat, grant, releases, ai-model-platform, news |
EntitlementsService |
StreamSnapshot |
ai-gateway, moochat, grant, releases, ai-model-platform, news |
UsageService |
Reserve |
ai-gateway |
UsageService |
Settle |
ai-gateway |
The contract is entitlements.proto, package moonitoring.farm.entitlements.v1:
// Proposed contract, version 1. Status: proposal for review, not confirmed design.
//
// Synchronous calls about what an Organization has and how much it used. Entitlements are a domain of farm (decided 2026-10-30, D2).
// Callers: ai-gateway (Reserve before a model call, Settle after it, in one statement each; req 69),
// every system (Check when its cached copy is missing or stale, StreamSnapshot at start-up; req 68),
// releases (Check of the features a channel requires; req 111.8), moochat (Check of a tool's features; req 122.5).
// The callers listed are authentication only (decided 2026-11-11): each RPC below names who may call it and what
// it sees, and refuses anyone else with PERMISSION_DENIED.
// Deadline: Check 500 ms, Reserve and Settle 500 ms, StreamSnapshot 60 s.
// x-moonitoring-callers: ai-gateway, moochat, grant, releases, ai-model-platform, news
// x-moonitoring-requirements: 68, 69, 111.8, 122.5
syntax = "proto3";
package moonitoring.farm.entitlements.v1;
import "google/protobuf/timestamp.proto";
service EntitlementsService {
// Whether an Organization holds a feature now, with the limits that apply.
// Callers: every system of the service's list. Sees: the answer for the Organization and feature it asks about.
rpc Check(CheckRequest) returns (CheckResponse);
// Streams the active entitlements, as of one write of entitlements, to bootstrap a system's cache.
// Callers: every system of the service's list. Sees: the active entitlements, without usage.
rpc StreamSnapshot(StreamSnapshotRequest) returns (stream StreamSnapshotResponse);
}
service UsageService {
// Reserves usage of a metered feature before the work: checks the limit and adds the reservation atomically.
// A retry with the same request_id returns the same reservation and is not counted twice.
// x-moonitoring-callers: ai-gateway
// Callers: ai-gateway only, which meters every model call. Sees: its own reservations.
rpc Reserve(ReserveRequest) returns (ReserveResponse);
// Settles a reservation after the work with the actual amounts; the difference is released.
// x-moonitoring-callers: ai-gateway
// Callers: ai-gateway only. Sees: only the reservations it made.
rpc Settle(SettleRequest) returns (SettleResponse);
}
message CheckRequest {
// Exactly one of organization_id and moonitoring_user_id is set.
string organization_id = 1;
string moonitoring_user_id = 2;
// e.g. farm.models.mastitis.
string feature = 3;
}
message CheckResponse {
bool entitled = 1;
string entitlement_id = 2;
// The entitlement's limits, as a JSON object; empty means no limit.
string limits_json = 3;
// When the entitlement ends; unset when open.
google.protobuf.Timestamp valid_until = 4;
}
message StreamSnapshotRequest {
string organization_id = 1;
}
message StreamSnapshotResponse {
string as_of_event_id = 1;
Entitlement entitlement = 2;
// The moment the snapshot was read, as in the snapshot of access (decided 2026-11-05).
google.protobuf.Timestamp as_of = 3;
}
message Entitlement {
string id = 1;
string organization_id = 2;
string feature = 3;
google.protobuf.Timestamp valid_from = 4;
google.protobuf.Timestamp valid_until = 5;
string limits_json = 6;
}
message ReserveRequest {
// The caller's request id; the same id reserves once.
string request_id = 1;
string organization_id = 2;
string moonitoring_user_id = 3;
string feature = 4;
// Period in the Organization's timezone, e.g. 2026-10; empty: the current one.
string period = 5;
Amounts amounts = 6;
}
message Amounts {
int64 requests = 1;
int64 input_tokens = 2;
int64 output_tokens = 3;
int64 cost_micros = 4;
}
message ReserveResponse {
string reservation_id = 1;
ReserveOutcome outcome = 2;
// What remains in the period after this reservation.
Amounts remaining = 3;
// What the entitlement says happens at 100 %: block, degrade or bill.
string at_limit = 4;
}
// Past the limit, an entitlement whose at_limit is degrade or bill still answers RESERVED, with remaining at or
// below zero, so the usage is counted; the caller degrades (ai-gateway moves to the active lite profile) or goes on.
// LIMIT_REACHED means the work must not run (at_limit block) and reserves nothing.
enum ReserveOutcome {
RESERVE_OUTCOME_UNSPECIFIED = 0;
RESERVE_OUTCOME_RESERVED = 1;
RESERVE_OUTCOME_LIMIT_REACHED = 2;
RESERVE_OUTCOME_NOT_ENTITLED = 3;
}
message SettleRequest {
string reservation_id = 1;
Amounts actual = 2;
}
message SettleResponse {
Amounts period_total = 1;
}
5.5.2.10.4 Contract v1¶
Proposed version
v1 is a proposal for review: its endpoints, errors and capabilities were designed from the requirements and the flows and are not confirmed. It leaves proposal with its first release; from then on it changes only as described in Every API Is Versioned.