Docs / Concepts / Plan-Variant Entitlements

Plan-Variant Entitlements

How to attach billable metrics to plan variants with type-shaped values, giving each tier different feature access, caps, and configurations.

Mental Model

Think of plan-variant entitlements as the feature matrix row for a pricing tier. Each cell says what that tier gets for a specific metric — on/off, a cap, a config blob, or credit-metered access.

Quick Take
Each attachment links one billable metric to one plan variant with a type-shaped value
Value shape must match the metric type: boolean needs enabled, gauge needs cap
Customers inherit entitlements from their subscription's plan variant — no per-customer overrides (yet)
Metered metrics don't need explicit attachments — they're governed by credit grants + metering rules

Plan-Variant Entitlements

A plan-variant entitlement is the link between a plan variant and a billable metric. It declares what a specific pricing tier gives its customers — SSO access (boolean), a seat cap (gauge), a config blob (static), or simply credit-metered access.

When a customer subscribes to a plan variant, they inherit all its entitlement attachments. Your app reads these values to gate features, enforce limits, and apply configuration.

How it works

  1. You create a billable metric with a type and default_value.
  2. You attach that metric to a plan variant with a value override — the specific value this tier provides.
  3. Customers subscribing to that variant inherit the attached value. If no attachment exists for a metric, the metric’s default_value applies.

The value you attach must match the metric’s type:

Metric typeRequired value shapeExample
boolean{"enabled": <bool>}{"enabled": true}
gauge{"cap": <non-negative integer>}{"cap": 50}
static{"config": <any object>}{"config": {"rpm": 1000}}
metered{} or omit{}

Metered metrics don’t need explicit attachments — they’re governed by credit grants and metering rules. You can still attach them to mark that a variant “includes” a metered metric, but the value has no effect on credit behavior.

Attaching a metric to a plan variant

POST /v1/plans/{plan_id}/variants/{variant_id}/entitlements
curl -X POST https://api.quotastack.io/v1/plans/plan_01/variants/var_pro_monthly/entitlements \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attach-sso-pro" \
  -d '{
    "billable_metric_key": "sso",
    "value": {"enabled": true}
  }'

Response (201 Created):

{
  "plan_id": "plan_01",
  "variant_id": "var_pro_monthly",
  "billable_metric_key": "sso",
  "value": {"enabled": true},
  "created_at": "2026-05-24T10:00:00Z"
}

Listing variant entitlements

GET /v1/plans/{plan_id}/variants/{variant_id}/entitlements
curl https://api.quotastack.io/v1/plans/plan_01/variants/var_pro_monthly/entitlements \
  -H "X-API-Key: qs_live_..."

Response:

{
  "data": [
    {
      "billable_metric_key": "sso",
      "value": {"enabled": true},
      "metric_type": "boolean",
      "created_at": "2026-05-24T10:00:00Z",
      "updated_at": "2026-05-24T10:00:00Z"
    },
    {
      "billable_metric_key": "max_seats",
      "value": {"cap": 50},
      "metric_type": "gauge",
      "created_at": "2026-05-24T10:01:00Z",
      "updated_at": "2026-05-24T10:01:00Z"
    }
  ]
}

Updating an entitlement value

PATCH /v1/plans/{plan_id}/variants/{variant_id}/entitlements/{billable_metric_key}
curl -X PATCH https://api.quotastack.io/v1/plans/plan_01/variants/var_pro_monthly/entitlements/max_seats \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "value": {"cap": 100}
  }'

The new value must still match the metric’s type. You cannot change the metric key — only the value.

Detaching an entitlement

DELETE /v1/plans/{plan_id}/variants/{variant_id}/entitlements/{billable_metric_key}
curl -X DELETE https://api.quotastack.io/v1/plans/plan_01/variants/var_pro_monthly/entitlements/sso \
  -H "X-API-Key: qs_live_..."

Returns 204 No Content. After detaching, customers on this variant fall back to the metric’s default_value.

Validation rules

The API enforces type-safe values at write time:

Metric typeValidationError on violation
booleanvalue must contain "enabled" (boolean)422 — invalid value shape
gaugevalue must contain "cap" (non-negative integer)422 — invalid value shape
staticvalue must contain "config" (any JSON object)422 — invalid value shape
meteredNo shape requirement

Error responses

StatusConditionMeaning
404Plan, variant, or metric not foundThe referenced resource doesn’t exist.
409Metric already attached to this variantDuplicate. Use PATCH to update or DELETE first.
422Value doesn’t match metric typeShape violation — see validation table above.

Worked example: Free vs Pro

A SaaS app defines four billable metrics:

Metric keyTypeDefault value
ssoboolean{"enabled": false}
max_seatsgauge{"cap": 5}
api_callmetered{}
model_accessstatic{"config": {"models": ["gpt-3.5"]}}

The Free variant attaches:

MetricValueEffect
sso{"enabled": false}No SSO
max_seats{"cap": 5}5 seats
model_access{"config": {"models": ["gpt-3.5"]}}Basic models only

The Pro variant attaches:

MetricValueEffect
sso{"enabled": true}SSO enabled
max_seats{"cap": 50}50 seats
model_access{"config": {"models": ["gpt-4", "claude-sonnet", "gpt-3.5"]}}All models

Neither variant explicitly attaches api_call — it’s metered, so access is governed by whether the customer has credits and an active metering rule.

When a customer subscribes to the Pro variant, your app can query their plan-variant entitlements and enforce: SSO is on, up to 50 seats, and the full model list is available. When they downgrade to Free, the values update accordingly.

Common Mistakes

The mistakes developers typically make with this concept — and what to do instead.

×
Don't attach the same metric to a variant twice
Why
The unique constraint rejects it with a 409. Detach first, or use PATCH to update the value.
×
Don't use gauge with a float cap
Why
Cap must be a non-negative integer. The API rejects fractional values with a 422.
🤖
Building with an AI agent?
Get this page as markdown: /docs/concepts/plan-variant-entitlements.md · Full index: /llms.txt