Docs / Cookbook / Setting Up a SaaS Pricing Matrix with Typed Entitlements

Setting Up a SaaS Pricing Matrix with Typed Entitlements

End-to-end walkthrough of defining typed billable metrics and attaching them to plan variants to build a complete Free vs Pro feature matrix.

Setting Up a SaaS Pricing Matrix with Typed Entitlements

This recipe walks through building a complete pricing matrix using all four metric types. By the end, you’ll have a Free and Pro tier with boolean feature flags, seat caps, model access config, and credit-metered API calls.

Step 1: Create the billable metrics

Define the four metrics that make up your pricing matrix. Each has a type and a sensible default value.

SSO access (boolean):

curl -X POST https://api.quotastack.io/v1/billable-metrics \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: metric-sso" \
  -d '{
    "key": "sso",
    "name": "SSO Access",
    "description": "Single sign-on via SAML/OIDC",
    "type": "boolean",
    "default_value": {"enabled": false}
  }'

Team seats (gauge):

curl -X POST https://api.quotastack.io/v1/billable-metrics \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: metric-max-seats" \
  -d '{
    "key": "max_seats",
    "name": "Team Seats",
    "description": "Maximum team members allowed",
    "type": "gauge",
    "default_value": {"cap": 1}
  }'

API calls (metered):

curl -X POST https://api.quotastack.io/v1/billable-metrics \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: metric-api-call" \
  -d '{
    "key": "api_call",
    "name": "API Call",
    "description": "One API request to the service"
  }'

No type needed — defaults to metered.

Model access (static):

curl -X POST https://api.quotastack.io/v1/billable-metrics \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: metric-model-access" \
  -d '{
    "key": "model_access",
    "name": "AI Model Access",
    "description": "Which AI models are available",
    "type": "static",
    "default_value": {"config": {"models": []}}
  }'

Step 2: Attach metrics to the Free variant

Assuming you have a plan plan_01 with a Free variant var_free:

# SSO off
curl -X POST https://api.quotastack.io/v1/plans/plan_01/variants/var_free/entitlements \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attach-free-sso" \
  -d '{"billable_metric_key": "sso", "value": {"enabled": false}}'

# 5 seats
curl -X POST https://api.quotastack.io/v1/plans/plan_01/variants/var_free/entitlements \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attach-free-seats" \
  -d '{"billable_metric_key": "max_seats", "value": {"cap": 5}}'

# Basic models only
curl -X POST https://api.quotastack.io/v1/plans/plan_01/variants/var_free/entitlements \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attach-free-models" \
  -d '{"billable_metric_key": "model_access", "value": {"config": {"models": ["gpt-3.5"]}}}'

No attachment needed for api_call — it’s metered, governed by credit grants and the metering rule.

Step 3: Attach metrics to the Pro variant

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

# 50 seats
curl -X POST https://api.quotastack.io/v1/plans/plan_01/variants/var_pro/entitlements \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attach-pro-seats" \
  -d '{"billable_metric_key": "max_seats", "value": {"cap": 50}}'

# All models
curl -X POST https://api.quotastack.io/v1/plans/plan_01/variants/var_pro/entitlements \
  -H "X-API-Key: qs_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attach-pro-models" \
  -d '{"billable_metric_key": "model_access", "value": {"config": {"models": ["gpt-4", "claude-sonnet", "gpt-3.5"]}}}'

Step 4: Verify the matrix

List entitlements for each variant to confirm the setup:

# Free variant
curl https://api.quotastack.io/v1/plans/plan_01/variants/var_free/entitlements \
  -H "X-API-Key: qs_live_..."
{
  "data": [
    {"billable_metric_key": "sso", "value": {"enabled": false}, "metric_type": "boolean"},
    {"billable_metric_key": "max_seats", "value": {"cap": 5}, "metric_type": "gauge"},
    {"billable_metric_key": "model_access", "value": {"config": {"models": ["gpt-3.5"]}}, "metric_type": "static"}
  ]
}
# Pro variant
curl https://api.quotastack.io/v1/plans/plan_01/variants/var_pro/entitlements \
  -H "X-API-Key: qs_live_..."
{
  "data": [
    {"billable_metric_key": "sso", "value": {"enabled": true}, "metric_type": "boolean"},
    {"billable_metric_key": "max_seats", "value": {"cap": 50}, "metric_type": "gauge"},
    {"billable_metric_key": "model_access", "value": {"config": {"models": ["gpt-4", "claude-sonnet", "gpt-3.5"]}}, "metric_type": "static"}
  ]
}

Step 5: How customers inherit entitlements

When a customer subscribes to the Pro variant, they “have”:

  • SSO: enabled (boolean check)
  • Seats: up to 50 (gauge check)
  • Models: GPT-4, Claude Sonnet, GPT-3.5 (static config read)
  • API calls: as many as their credit balance allows (metered, standard entitlement check)

Your application code reads these values and enforces them:

  • At login: check the sso entitlement to decide whether to redirect to the SAML provider
  • At team invite: check max_seats against current team size
  • At model selection: read model_access config and filter the model picker
  • Before each API call: run a standard credit-based entitlement check on api_call

Updating entitlements mid-cycle

If you upgrade Pro from 50 to 100 seats mid-cycle:

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

All customers on the Pro variant immediately inherit the updated cap — no migration, no per-customer update needed.

Common pitfalls

  • Duplicate attach: If you try to attach sso to the Pro variant a second time, you get a 409. Use PATCH to update the value, or DELETE then re-attach.
  • Wrong value shape: Attaching {"cap": 50} to a boolean metric returns 422. The value shape must match the metric type.
  • Float caps: {"cap": 5.5} is invalid for gauge metrics. Caps must be non-negative integers.
  • Forgetting defaults: If you don’t attach a metric to a variant, the metric’s default_value applies. Make sure your defaults make sense for the “no attachment” case.
🤖
Building with an AI agent?
Get this page as markdown: /docs/cookbook/entitlement-types-setup.md · Full index: /llms.txt