quotastack Docs
Docs / API / Metering rules

Metering rules

What one unit of a metric costs.

A metering rule prices one billable metric. The rule sets how many millicredits one unit costs.

The price can be flat, per unit, or tiered by how much a customer used. QuotaStack finds the active rule and debits the balance each time a usage event comes in.

Which call do I want?

2 of 2 operations documented in full.

List metering rules

GET/v1/metering-rules
Idempotency-KeyNot used. This is a read.
EnvironmentSandbox and Live
AuthTenant API key
WritesNothing. A read has no side effects.
Fires No webhooks.

This endpoint lists metering rules, oldest first. Filter by billable_metric_key for one metric’s price history. Add active_only=true to see only the rule charged today.

Query parameters
FieldTypeMeaning
billable_metric_keyoptionalstring

Only rules for this metric key.

If you leave it out: You get every rule for this metric.

active_onlyoptionalboolean

Only the one rule charged today for each metric — the rule with no effective_until set.

If you leave it out: You get every rule, old and new.

cursoroptionalstring

Opaque pagination cursor from the previous page's pagination.next_cursor. Omit to start at the first page.

limitoptionalinteger

Page size. Default 20, max 100.

Response 200
{
  "data": [
    {
      "id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a53",
      "billable_metric_key": "chat_message",
      "cost_type": "per_unit",
      "base_cost": 0,
      "unit_cost": 500,
      "tier_config": null,
      "effective_from": "2026-07-20T09:00:00Z",
      "effective_until": null,
      "metadata": {},
      "created_at": "2026-07-20T09:00:00Z",
      "updated_at": "2026-07-20T09:00:00Z"
    }
  ],
  "pagination": {
    "has_more": false,
    "next_cursor": null
  }
}
Response fields
FieldTypeMeaning
datarequiredarray

One entry per metering rule, oldest first. Old rules stay in the list unless you add active_only=true.

paginationrequiredobject

Cursor-based pagination envelope. Returned on every list endpoint. No total — cursor-only.

Create a metering rule

POST/v1/metering-rules
Idempotency-KeyRequired. Returns 422 without it.
EnvironmentSandbox and Live
AuthTenant API key
WritesOne new metering rule, active right away. If the metric had an old rule, QuotaStack turns it off. If the billable metric itself did not exist yet, QuotaStack makes one.
Fires No webhooks.

Creating a rule sets the price for one billable metric. If billable_metric_key does not match one that exists, QuotaStack makes a plain one — type metered, named after the key. If a rule is already active for this key, QuotaStack turns it off first. Only one rule stays active per metric.

Header parameters
FieldTypeMeaning
Idempotency-Keyrequiredstring

A unique string you choose, up to 256 characters. It stops a retry from doing the work twice.

This header is required on every POST and PATCH. Leave it out and the request fails with 422, before any change is made.

Send the same key twice and QuotaStack replays the first response. The second call's status and body match the first, and the response carries X-Idempotent-Replayed: true. Replays are available for 24 hours.

Derive the key from the business event rather than a random value, so a retry from anywhere reuses it — for example topup:{payment_intent_id} or renewal:{subscription_id}:{period_start}.

Body parameters
FieldTypeMeaning
billable_metric_keyrequiredstring

The key of the billable metric this rule prices.

If you leave it out: QuotaStack rejects the call. This field is required.

cost_typerequiredstring

How QuotaStack turns units used into a charge.

If you leave it out: QuotaStack rejects the call. This field is required.

  • flatOne fixed charge per consume call, no matter how many units. Set it with base_cost; unit_cost and tier_config are unused.
  • per_unitunit_cost times the units in that call. Set unit_cost; base_cost is stored but never charged for this type.
  • tieredPriced by tier_config, a price ladder keyed to how many units the call used. base_cost is stored but never charged for this type.
base_costoptionalinteger (int64)

The flat charge for a flat rule. Stored either way, but never charged for per_unit or tiered.

Unit: millicredits, where 1 credit is 1000 millicredits.

If you leave it out: Required for flat. QuotaStack sets it to 0 by default for per_unit and tiered.

unit_costoptionalinteger (int64)

The charge per unit for a per_unit rule. Unused for flat. A tiered rule sets its own unit_cost per tier instead.

Unit: millicredits, where 1 credit is 1000 millicredits.

If you leave it out: Required, and must be over zero, for per_unit. Unused otherwise, so you may leave it out.

tier_configoptionalunknown

The price ladder for a tiered rule. mode is graduated (each tier prices its own slice of the units) or volume (one tier prices every unit). Each tier sets up_to (its top unit count, null on the last tier only). Each tier also sets unit_cost (millicredits per unit in that tier) and flat_cost (a one-time millicredit charge for entering the tier).

If you leave it out: Required for tiered. QuotaStack rejects the call without it. Unused for flat and per_unit.

metadataoptionalobject

Your own key-value tags. QuotaStack stores them unchanged and returns them on every read.

If you leave it out: Left out, QuotaStack stores {}.

Request
{
  "billable_metric_key": "chat_message",
  "cost_type": "per_unit",
  "unit_cost": 500
}
Response 201
{
  "id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a53",
  "billable_metric_key": "chat_message",
  "cost_type": "per_unit",
  "base_cost": 0,
  "unit_cost": 500,
  "tier_config": null,
  "effective_from": "2026-07-20T09:00:00Z",
  "effective_until": null,
  "metadata": {},
  "created_at": "2026-07-20T09:00:00Z",
  "updated_at": "2026-07-20T09:00:00Z"
}
Response fields
FieldTypeMeaning
idrequiredstring (uuid)
tenant_idrequiredstring (uuid)
billable_metric_keyrequiredstring

The key of the billable metric this rule prices.

cost_typerequiredstring

How QuotaStack turns units used into a charge.

  • flatOne fixed charge per consume call, no matter how many units. Set it with base_cost; unit_cost and tier_config are unused.
  • per_unitunit_cost times the units in that call. Set unit_cost; base_cost is stored but never charged for this type.
  • tieredPriced by tier_config, a price ladder keyed to how many units the call used. base_cost is stored but never charged for this type.
base_costoptionalinteger (int64)

The flat charge for a flat rule. Stored either way, but never charged for per_unit or tiered.

Unit: millicredits, where 1 credit is 1000 millicredits.

unit_costoptionalinteger (int64)

The charge per unit for a per_unit rule. Unused for flat and tiered.

Unit: millicredits, where 1 credit is 1000 millicredits.

tier_configoptionalunknown

The price ladder for a tiered rule. mode is graduated (each tier prices its own slice of the units) or volume (one tier prices every unit). Each tier sets up_to (its top unit count, null on the last tier only). Each tier also sets unit_cost (millicredits per unit in that tier) and flat_cost (a one-time millicredit charge for entering the tier). null for flat and per_unit rules.

effective_fromrequiredstring (date-time)

When this rule started pricing its metric, the moment you made it.

effective_untiloptionalstring (date-time)

null until a new rule takes over. Then QuotaStack sets the time here.

metadatarequiredobject

Your own key-value tags, unchanged since the last write.

created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)

Errors

  • 422billable_metric_key or cost_type is missing, or a field cost_type needs is wrong: base_cost for flat, a unit_cost over zero for per_unit, or a valid tier_config for tiered. The response names the field. validation-error