Limit Plans, Assignments & Defaults API
Every endpoint on this page lives under /api/** — the same surface the manager's own Angular UI calls — not under /apiops/**. The plan catalog, Limit Assignments, and Bulk Assignment each have a portable Management API counterpart, linked from their own sections; Default Limit Policies does not.
For the concepts behind these endpoints — plan activation, target audience, how a plan is counted, and rule assignments — see Limit Plans.
The portable, name-based Management API counterpart of the plan catalog below — create a plan, save its rule body, activate, deactivate and delete it through APIops.
Endpoints
Limit Plans — /api/limit-plans
The catalog. A plan holds its own rule body and an active flag; it keeps no revisions and no drafts. A plan is either active (the gateways enforce it) or inactive (it limits nothing; its rule body, assignments and counters are kept). A saved rule body or target audience applies at once: on an active plan, every assignment that references it is re-pushed to the gateways. Every endpoint below takes an optional projectId query parameter with the same meaning: absent addresses the installation-wide platform catalog (GET/list still returns a project's own plans plus the platform ones; every other by-key endpoint addresses the platform row directly), present addresses one project's own catalog. Writing a platform-scope row is restricted to a system administrator; a project-scoped caller naming a platform plan's key is refused.
Reads:
GET /api/limit-plans— list plans (projectIdoptional — absent addresses the platform-wide catalog; with a project id the answer is that project's own plans plus the platform catalog;familyoptional;includeManaged=truealso lists the profiles owned by portal subscription plans;allProjects=true, system administrator only, lists every scope at once)GET /api/limit-plans/{planKey}— one plan, with its rule body (targets named) and itsactiveflagGET /api/limit-plans/{planKey}/audience— the plan's target audience (selected identities and the caller condition), including how each identity is countedGET /api/limit-plans/{planKey}/delete-impact— what deleting the plan takes with itGET /api/limit-plans/bodies— the rule body of each plan named inplanIds, with target names, in one read
Writes:
POST /api/limit-plans— create a plan with its rule body (initialRuleSpec); the plan is created activePUT /api/limit-plans/{planKey}— update a plan's name, description, or labels (not its rule body)PUT /api/limit-plans/{planKey}/rule-spec— save the plan's limits; on an active plan they reach the gateways at once. An optionalversionrefuses a save over a plan changed meanwhilePOST /api/limit-plans/{planKey}/rule-spec/impact— what saving a rule body would change against the stored one; nothing is writtenPOST /api/limit-plans/{planKey}/activate— the gateways enforce the plan again for every assignment that references it (optionalversionquery parameter)POST /api/limit-plans/{planKey}/deactivate— stop enforcing the plan on every gateway; the rule body, the assignments and the counters are kept (optionalversionquery parameter)POST /api/limit-plans/{planKey}/duplicate— copy the plan's limits into a new plan (body:name, optionaldescription); the target audience is not copiedPOST /api/limit-plans/{planKey}/audience/impact— what saving the target audience would change, identity by identity; nothing is writtenPUT /api/limit-plans/{planKey}/audience— save the target audience; the change reaches the gateways at oncePUT /api/limit-plans/{planKey}/audience/list-behavior— save the plan's condition settings (request condition and error messages); applied at onceDELETE /api/limit-plans/{planKey}— delete the plan in any state: an active plan is deactivated first, its assignments and creation defaults stop naming it, and the plan is removed
The screen also reads a few helper lists: POST /api/limit-plans/target-authentication (for each API proxy or endpoint target, whether it authenticates its callers — the plan editor warns when a plan identifies callers by authentication but the target does not authenticate), GET /api/limit-plans/audience-candidates (identities that can be added to a target audience), POST /api/limit-plans/{planKey}/audience-overlaps and GET /api/limit-plans/{planKey}/taken-targets (limits that overlap another plan of the same identities), and GET /api/limit-plans/target-options/endpoints (the endpoints of an API proxy).
Plans no longer keep revisions. The revision endpoints (.../revisions, .../revisions/{revision}, .../draft, .../published, .../published-revisions, .../draft-revisions, .../revisions/{revision}/publish, DELETE .../draft), change-preview, and the deploy / undeploy endpoints no longer exist on this surface; use rule-spec, activate and deactivate. The retire, republish and redeploy endpoints were removed earlier.
Limit Assignments — /api/limit-bindings
One assignment applies one plan to one identity (an organization, consumer, application or API client). Its lifecycle is DRAFT → ACTIVE → ENDED. On the Limits tab, a plan added to an identity is created ACTIVE and goes into force at once. Removing an ACTIVE assignment is ending it, so the record of when a limit stopped applying is kept (the Removed Limit Plans table); only a DRAFT, which was never in force, can be discarded. A portable, name-based equivalent of this same single-assignment surface is also exposed on the Management API — see Limit Assignments Management API.
GET /api/limit-bindings— list assignments (projectId,family,statusall optional; an absentstatusincludes drafts and ended rows). Every list endpoint below returns summary rows that also carry read-only display names next to the ids —subjectName(consumer username, API client / application / organization / proxy name; absent forAUDIENCE_RULE, an endedPROJECT/PLATFORMrow, or a deleted subject) andtarget.targetName(proxy / proxy group name for a narrowed target) — both ignored on writeGET /api/limit-bindings/subject— every assignment naming one subject (subjectTyperequired;activeOnly=truereturns only the live one, if any)GET /api/limit-bindings/inherited?subjectType&subjectId— the plans an identity gets from an organization or consumer above it through an "Each …" counting choice (the nearest one per family);subjectTypeisAPI_CLIENT(subjectIdis the client id),CONSUMERorORGANIZATIONGET /api/limit-bindings/inheritance-summaries?bindingKeys=…— for each "Each …" assignment, how many identities of that kind sit beneath its subject and how many of them have an assignment of their own in the same familyGET /api/limit-bindings/plan-overlaps?subjectType&subjectId&family— the plans whose limits overlap an open assignment of the identityGET /api/limit-bindings/covering-api-proxy?projectId=X&apiProxyId=Y— everyACTIVEREQUEST_RATEassignment whose target covers this API proxy: explicit-subject and rule-based (AUDIENCE_RULE) assignments alike.apiProxyIdis required;projectIdis optional and defaults to the proxy's own project. Returns the list-row (LimitPolicyBindingSummaryDTO) shape, same as every other list endpoint on this page — this is what backs the "Rate Limit" badge and its dialog on the proxy's Develop screen.GET /api/limit-bindings/{bindingKey}— one assignmentGET /api/limit-bindings/referencing-plan/{planId}— impact analysis: every assignment that references a given planPOST /api/limit-bindings— create an assignment. The manager screens createPLAN-mode assignments:mode: PLANwith the plan's id inplanIds. The API also acceptsCUSTOM(an inlinecustomRuleSpec, no plan) andOFF(no local limit; limits above the identity still apply).INHERITis refused.- A
PROJECTorPLATFORMsubject is refused on create, import-create, update, activate and bulk with400, errorKeylimit.binding.scopeSubjectRemoved: project and platform limits were removed. Ending aPROJECT/PLATFORMrow that is already stored still works (system administrator only). TheGET /api/limit-bindings/scope-subjectsendpoint no longer exists. PUT /api/limit-bindings/{bindingKey}— edit an assignment's content:mode,planIds,customRuleSpec,audienceRule,assignmentMode/inheritTo,cacheErrorHandlingType,cacheConnectionTimeoutInSeconds,showRateLimitStatisticsInResponseHeader,customMessageTemplate/customMessageContentType/customMessageHttpStatusCode,validFrom/validUntil, and the caller's observedversion— its subject and scope (subjectType,subjectId,actorScope,family,targetincluding the HTTP method axis) cannot be changed this way; every other field on the request body is silently ignored on updatePOST /api/limit-bindings/{bindingKey}/activate— put a saved (DRAFT) assignment into forcePOST /api/limit-bindings/{bindingKey}/end— end a live assignment (optional reason)DELETE /api/limit-bindings/{bindingKey}— discard aDRAFTassignment; it leaves no historyPUT /api/limit-bindings/{bindingKey}/override— on the assignment of an application that comes from its portal subscription plan, pin the content you send so a later change of the subscription plan no longer updates it; on any other assignment it is an ordinary editDELETE /api/limit-bindings/{bindingKey}/override— remove the pin; the row returns to its subscription plan (optionalexpectedVersion)POST /api/limit-bindings/validate— dry-run every save-time rule without writing anythingGET /api/limit-bindings/targets— the targets that rule assignments sit on, grouped, with the out-of-target setting each carriesPUT /api/limit-bindings/targets/out-of-target— set the out-of-target action (and, forGENERAL_QUOTA, its mode and windows) of one target on every active rule assignment that shares it; see Rule AssignmentsPOST /api/limit-bindings/targets/unify— for a target whose active rule assignments disagree, apply the most restrictive value they already carry to all of them
Two limits on what an identity can hold: an identity can carry several plans of one family, each counted on its own, but two assignments counted the same way cannot limit the same API, endpoint or AI proxy. A plan has no general limit: every limit in a plan body names its own target. Only the inline custom limit of an assignment can be general, and one identity cannot hold two of those (see Limit Assignments). A create or an edit that would do so is refused. When a request condition separates the two plans, the overlap is only reported by plan-overlaps.
How an organization, consumer or application counts a plan — assignmentMode, inheritTo
This is the Counted As choice of the Limits tab. It applies to ORGANIZATION, CONSUMER and APPLICATION subjects; every other subject type is always counted on its own. Set it on create; it may be repeated or left out on update (the stored value is kept).
assignmentMode | inheritTo | Counted As |
|---|---|---|
SELF (default when absent) | — | The subject's own total: one counter for everything under it, the API clients of its consumers and applications included |
DESCENDANTS | API_CLIENT (default when absent) | Each API client beneath the subject that has no assignment of its own gets the plan with its own counter |
DESCENDANTS | CONSUMER | Each consumer (and application) beneath an organization, same rule. Organization only |
DESCENDANTS | ORGANIZATION | Each sub-organization beneath an organization, same rule; the organization's direct members (its consumers and applications and their API clients) also share one more counter. Organization only |
With DESCENDANTS the subject itself is not counted — except an organization with inheritTo = ORGANIZATION, whose direct members are counted together in one counter. The nearest organization or consumer above an identity that carries such an assignment wins.
Target — target
target.type narrows what the assignment counts: ALL (the default, no narrowing), API_PROXY, API_PROXY_ENV, API_PROXY_GROUP, API_PROXY_GROUP_ENV, API_ENDPOINT, AI_MODEL, or AI_PROVIDER. target.targetId and target.environmentId are present or absent depending on the type (an _ENV type carries both; ALL carries neither; API_ENDPOINT carries targetId — the ApiMethod id — but no environmentId and no httpMethods axis, since it already narrows to a single method). An AI_MODEL target names one model of one LLM provider: its targetId is the provider's id and the model identifier joined by /, and the assignment counts only the traffic that provider's model served. API_ENDPOINT is written by the legacy limit migration at upgrade (see Legacy Limits Migrated at Upgrade); the manager UI does not yet offer it as a choice when creating a new assignment by hand.
target.httpMethods — a list of HTTP methods, on an API_PROXY/API_PROXY_ENV target only — additionally narrows the assignment to those methods; empty or absent means every method. target.methodSignature is response-only: it is derived from httpMethods (GET+POST) and echoed back on every read, but a value sent for it on POST/PUT is ignored — the server always recomputes it. A 400 with errorKey limit.binding.methodAxisNotAllowed is returned for an httpMethods list on a target type that does not support one, or for a method token the server does not recognize.
The target (the HTTP method axis included) is part of the assignment's identity and cannot be changed by PUT — change it by ending the assignment and creating a new one.
Rule Assignments — subjectType: "AUDIENCE_RULE"
An assignment whose subject is a condition (the plan's Callers Matching the Condition) rather than one fixed identity. subjectType is AUDIENCE_RULE; subjectId is assigned by the server (it is the assignment's own bindingKey) and any value sent for it is overwritten. actorScope may be omitted: it is then derived from audienceRule.identitySource — AUTH_RESOLVED → AUTHENTICATED, VARIABLE → ANY (an explicit value is kept). Both families support rule assignments. The general quota that an out-of-target action GENERAL_QUOTA applies must match the family: generalQuotaWindows for REQUEST_RATE, generalQuotaBudget (at least one token, USD or request-count ceiling) for AI_TOKEN_BUDGET; the other is refused with 400, errorKey limit.binding.audienceRuleFamily.
The condition itself is audienceRule, required for this subject type and forbidden for every other one (400, errorKey limit.binding.audienceRuleShape):
| Field | Type | Meaning |
|---|---|---|
identitySource | enum | AUTH_RESOLVED (default) or VARIABLE |
variableId | string | The global Variable's id — required when identitySource is VARIABLE |
operator | enum | A comparison operator (EQ, CONTAINS, STARTS_WITH, IN, …) — required |
value | string | Required |
outOfTargetAction | enum | BLOCK (default; shown as "Rejected (403)"), GENERAL_QUOTA, or NONE — NONE leaves identities outside the audience untouched: neither blocked nor counted. Omitting the field still means BLOCK, so an existing client keeps its behaviour. This setting belongs to the target, not to one assignment (Request Rate only): when another active rule assignment already sits on the same target, the value sent is replaced by the one that target carries. Change it for the whole target with PUT /api/limit-bindings/targets/out-of-target. |
generalQuotaMode | enum | TOTAL (default) or PER_IDENTITY — read only when outOfTargetAction is GENERAL_QUOTA |
generalQuotaWindows | array | REQUEST_RATE only. At least one window (same shape as a Request Rate plan's windows) — required when outOfTargetAction is GENERAL_QUOTA, ignored for BLOCK and NONE |
generalQuotaBudget | object | AI_TOKEN_BUDGET only. The AI token budget (same shape as a plan's aiBudget) with at least one positive token, USD or request-count ceiling — required when outOfTargetAction is GENERAL_QUOTA |
additionalClauses | array | Further conditions combined with OR with operator/value (each with its own identitySource, variableId, operator, value) |
identityRegexList | string[] | Regular expressions combined with OR with every other condition; the first capture group is the counted identity |
audienceRule is content, not scope: unlike target, it can be changed by PUT.
Enforcement Posture and Custom Message
These fields exist on every assignment regardless of family. All except showRateLimitStatisticsInResponseHeader are acted on for REQUEST_RATE assignments only; showRateLimitStatisticsInResponseHeader also applies to AI_TOKEN_BUDGET assignments. An AI_TOKEN_BUDGET assignment is enforced on every AI request, with or without the Token Rate Limit policy. The plan's own counter-store setting wins over the assignment's, and the plan's own overflow action applies — see Limit Plans:
| Field | Type | Meaning | Default when absent |
|---|---|---|---|
cacheErrorHandlingType | enum | FAIL rejects the request when the counter service is unreachable; CONTINUE lets it through uncounted | FAIL |
cacheConnectionTimeoutInSeconds | integer | Per-reservation timeout to the counter service | Platform default |
showRateLimitStatisticsInResponseHeader | boolean | Adds RateLimit-Remaining/RateLimit-Limit/RateLimit-Reset/X-RateLimit-Identity/X-RateLimit-Type to the response. For an AI_TOKEN_BUDGET assignment the headers come from the Limit Plan tier with the smallest share left, without X-RateLimit-Identity; an AI plan that sets its own value wins, an unset value uses this one | false |
customMessageTemplate | string | Replaces the standard message on a limit-exceeded block for this assignment only; same variable syntax as the platform's Error Messages screen | None (standard message applies) |
customMessageContentType | string | Content type of the custom message | application/json;charset=utf-8 when a template is set |
customMessageHttpStatusCode | integer | HTTP status of the custom message | 429 |
The custom message applies to a limit-exceeded block only (THROTTLING_STOP/QUOTA_STOP). It is not applied to a rule assignment's out-of-target block (ENDPOINT_RATELIMIT_IDENTITY_NOT_ALLOWED/ENDPOINT_RATELIMIT_IDENTITY_NOT_RESOLVED), which always uses the platform's standard error-message customization for those types.
Bulk Assignment — /api/limit-assignment-*
Attaches one assignment — a plan or a custom value — to a large, filtered population of subjects in a single run, instead of one POST /api/limit-bindings per subject. See Limit Plans → Bulk Assignment for the concepts (selection, conflict policy, run lifecycle, node-failure recovery). A portable, name-based equivalent of this same engine is also exposed on the Management API — see Bulk Limit Assignment API.
POST /api/limit-assignment-previews— classify a selector + content + conflict policy without writing anything: expected subject count (estimatedabove 5,000), how many would be created / skipped / replaced, how many are license-blocked, and a small sample of rows. Returns aselectorFingerprinta run must repeat.POST /api/limit-assignment-runs— queue a run over the selected population (202,Locationheader). The body repeats the preview'sselector/content/conflictPolicyplus itspreviewFingerprintandexpectedCount. Only one active run per project is allowed: a second call while one is queued or running is refused with409(error.limit.bulk.runAlreadyActive); a selector that no longer hashes topreviewFingerprintis409(error.limit.bulk.fingerprintMismatch).selector.includeIds/excludeIdsabove 5,000 entries is400(error.limit.bulk.includeListTooLarge).GET /api/limit-assignment-runs?projectId&page&size— the project's runs, newest first.GET /api/limit-assignment-runs/{runId}?projectId— one run's progress and outcome: status, phase, counters (created/replaced/skipped/failed/license-skipped), and deployment state.GET /api/limit-assignment-runs/{runId}/issues?projectId&page&size— the FAILED/SKIPPED subjects the run recorded (at most 1,000 kept per run; beyond that,issuesTruncated).POST /api/limit-assignment-runs/{runId}/actions/cancel— ask a queued or running run to stop at its next chunk boundary (200); everything already written stays written.POST /api/limit-assignment-runs/{runId}/actions/rollback— only on a finished Assign or Retry run: queue a new run that ends every assignment the source run created and re-opens what it replaced as new rows, counters restarting (202, a new run).POST /api/limit-assignment-runs/{runId}/actions/retry-failed— queue a new run over only the subjects the source run failed on, with Keep existing as its conflict policy (202, a new run).POST /api/limit-assignment-subjects/search?page&size&sort— the server-paged subject table behind the Assign tab.GET /api/limit-assignment-subjects/organizations?projectId&parentId— the lazily loaded organization tree.
Default Limit Policies — /api/limit-defaults
An owner's standing offer of a limit to children it will have or already has. The owner is a platform, a project, a consumer or an application. An organization does not own default limit plans any more: creating or updating a default with ownerType: ORGANIZATION is refused with 400, errorKey limit.default.organizationOwnerRetired. To limit the identities under an organization, apply a plan to the organization itself with Counted As set to Each API client, Each consumer or Each sub-organization and the direct members (see assignmentMode and inheritTo above). This surface has no dedicated manager UI screen in this version; it exists for direct integration use.
GET /api/limit-defaults/{defaultKey}— one default policy (projectIdabsent/blank addresses the platform-wide row)GET /api/limit-defaults— every default policy one owner has written (ownerTyperequired)POST /api/limit-defaults— createPUT /api/limit-defaults/{defaultKey}— update content (never the enabled/disabled state — see below)POST /api/limit-defaults/validate— dry-run every save-time rule without writing anythingPOST /api/limit-defaults/{defaultKey}/activate— enable the defaultPOST /api/limit-defaults/{defaultKey}/disable— disable it (existing assignments already materialized from it are unaffected)DELETE /api/limit-defaults/{defaultKey}— delete (refused while the row is enabled — disable it first)
Portal Subscription Linking
A portal API Product's Subscription Plan (ApiPlan) can reference an active, platform-scope Limit Plan per family instead of carrying its own numbers — see API Product → Limit Profiles and Limit Plans for the concepts. These two endpoints support that surface; the Subscription Plan CRUD endpoints themselves (/api/api-products/**, /api/api-product-app-register) are the manager's own portal-management REST API and are not otherwise catalogued on this page.
GET /api/api-products/{productId}/plans/{planId}/limit-impact— before saving a plan whose limit-profile references (or on-exceed setting) changed, returns how many approved subscriptions and distinct applications would start enforcing the new limits:approvedSubscriptionCount,familiesWithProfile(the families the plan carries an active reference for),affectedApplicationCount.POST /api/limit-bindings/portal-subscriptions/backfill?apply=false|true— system administrator only. One-shot repair for subscriptions that were approved before this reference model existed.apply=false(the default) previews the sweep without writing anything;apply=trueperforms it, one subscription at a time, so a subscription whose profile cannot be resolved does not stop the rest of the backlog. Response:apply,scanned(subscriptions examined),wouldCreateOrJoin,alreadyBound(subscription × family counts), and — on an applied run only —created,updated,shared,conflicts(oneappId:familystring per family left on another subscription's profile),failed(oneappId:messagestring per subscription the sweep could not sync, still pending).
PUT /api/api-product-app-register — approving or updating a subscription — additionally accepts acknowledgeLimitProfileSwitch: true in the request body to move an application's shared limit assignment to this subscription's profile when another approved subscription's profile currently holds it; omitted or false keeps the existing assignment and the response's limitProfileConflicts field names the families where the request's own preference was not applied.
Authentication
These are manager-application endpoints, authenticated the same way as the rest of the manager's own REST API — not by the Personal API Access Token that authenticates the /apiops/** surface documented elsewhere on this site.
Permissions
- Reads require the Identity permission at View; every write — including Bulk Assignment's previews, runs, and actions — requires it at Manage. The AI Budgets permission is also accepted in place of Identity.
- No license module is checked on these endpoints: an
AI_TOKEN_BUDGETplan or assignment is gated by permission exactly like aREQUEST_RATEone. (The AI Gateway menu entries of the manager screens keep their own licence gate.) projectId(query parameter on Limit Plans, Limit Assignments, Default Limit Policies, and Bulk Assignment) may be omitted to address the platform-wide scope instead of one project's own catalog. Reading platform rows is open to any caller with View in some project (they are what that project's picker also offers, badged Platform); writing one is reachable only by a system administrator, the same rule the rest of the manager's admin-scoped endpoints follow. Bulk Assignment has no platform-wide subject population — itsprojectIdalways addresses one project.
Notes
- Both families are usable.
AI_TOKEN_BUDGETandREQUEST_RATEplans can both be created, activated and applied — see Limit Plans for what each carries, and its Overflow Action (REQUEST_RATE:BLOCK/COUNT_ONLY,BLOCKwhen absent). - A plan keeps no revision history. Saving the rule body replaces it; on an active plan the new body reaches the gateways at once.
- A plan reference is never inlined. A
PLAN-mode assignment stores plan ids, not a copy of the plan's rule body — the plan's own rule body is what is resolved at request time. An assignment of a plan that is inactive limits nothing. OFFnarrows one subject; it does not widen anything above it. Ancestor ceilings (the organization) still apply to a subject with anOFFassignment. The manager screens do not offerOFF.- Both families enforce for real. An
ACTIVEREQUEST_RATEassignment of an active plan blocks traffic for real, evaluated at the authentication moment (429+Retry-Afteron an exhausted window). AnACTIVEAI_TOKEN_BUDGETassignment enforces the same way on every AI request, independent of the Token Rate Limit policy. See Limit Plans. - The active-scope key (
subjectType+subjectId+actorScope+family+target, HTTP methods included) is immutable.PUTreads only content off the body — see the Target note above; changing it means ending the assignment and creating a new one. AUDIENCE_RULEis its own subject type.subjectIdis minted by the server; the caller only ever suppliesaudienceRule. See Limit Plans for the concept.
Related Documentation
- Limit Plans - The manager UI screens this surface backs
- Limit Plans Management API - The portable, name-based Management API surface for the plan catalog above
- Limit Assignments Management API - The portable, name-based Management API surface for the single-assignment endpoints above
- Bulk Limit Assignment API - The portable, name-based Management API surface for the same bulk-assignment engine
- API Product - Referencing a platform Limit Plan from a portal Subscription Plan
- Token Rate Limit Policy - The limit of one AI proxy, which runs alongside plans
- Error Handling - Error response formats