quotastack Docs
Docs / API / Billable metrics

Billable metrics

The named things you charge for.

A billable metric is the named thing you charge for. One chat message, one API call, one gigabyte of storage — each is a metric with its own key.

A metric alone has no price. A metering rule sets the price for one unit, and a usage event reports that a customer used it.

Which call do I want?

4 of 4 operations documented in full.

List billable metrics

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

This page lists billable metrics, oldest first.

Query parameters
FieldTypeMeaning
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-4f6c8e1b3a52",
      "key": "chat_message",
      "name": "Chat message",
      "description": "One message sent in a chat session.",
      "status": "active",
      "type": "metered",
      "default_value": {},
      "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 row per billable metric, oldest first.

paginationrequiredobject

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

See also

Create a billable metric

POST/v1/billable-metrics
Idempotency-KeyNot required for this operation.
EnvironmentSandbox and Live
AuthTenant API key
WritesOne new billable metric. status is active right away.
Fires No webhooks.

Creating a billable metric names one thing your app meters or gates. Creating one needs an Idempotency-Key header, like every write. openapi.yaml skips it here, but QuotaStack still checks. The metric alone sets no price. Add a metering rule for that.

Body parameters
FieldTypeMeaning
keyrequiredstring

The name your code sends on every usage event and metering rule for this metric, like chat_message. Must be unique for your tenant.

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

namerequiredstring

A label for lists and dashboards.

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

descriptionoptionalstring

Longer, free text for dashboards.

If you leave it out: Left out, QuotaStack stores an empty string.

typeoptionalstring

What kind of entitlement this metric is, and what a check call returns for it.

If you leave it out: Left out, this metric is metered.

  • meteredPriced by a metering rule and paid for out of the customer’s balance. A check returns the balance and the estimated cost.
  • booleanA plain on/off flag, like SSO access. A check returns {"enabled": true} or {"enabled": false}, and costs nothing.
  • gaugeA count with a cap, like a seat limit. A check returns the cap and how many the customer has used so far.
  • staticA JSON value your app reads directly, like a list of models you allow. A check returns that value only.
default_valueoptionalobject

The starting value for this metric’s type. metered ignores this field entirely. boolean takes {"enabled": <bool>}. gauge takes {"cap": <non-negative integer>}. static takes any object, commonly {"config": ...}.

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

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
{
  "key": "chat_message",
  "name": "Chat message",
  "description": "One message sent in a chat session.",
  "type": "metered"
}
Response 201
{
  "id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a52",
  "key": "chat_message",
  "name": "Chat message",
  "description": "One message sent in a chat session.",
  "status": "active",
  "type": "metered",
  "default_value": {},
  "metadata": {},
  "created_at": "2026-07-20T09:00:00Z",
  "updated_at": "2026-07-20T09:00:00Z"
}
Response fields
FieldTypeMeaning
idrequiredstring (uuid)
tenant_idrequiredstring (uuid)
keyrequiredstring

The name your code sends with each use of this metric, and with its metering rule.

namerequiredstring
descriptionrequiredstring

Longer, free text for dashboards. An empty string unless you set one.

statusrequiredstring

Active or inactive, for your own records. QuotaStack does not use this to block usage today.

  • activeThe normal state for a metric in use.
  • inactiveA label only — checks and usage still work the same way.
typerequiredstring

What kind of entitlement this metric is, and what a check call returns for it. Fixed after creation.

  • meteredPriced by a metering rule and paid for out of the customer’s balance. A check returns the balance and the estimated cost.
  • booleanA plain on/off flag, like SSO access. A check returns {"enabled": true} or {"enabled": false}, and costs nothing.
  • gaugeA count with a cap, like a seat limit. A check returns the cap and how many the customer has used so far.
  • staticA JSON value your app reads directly, like a list of models you allow. A check returns that value only.
default_valuerequiredobject

The starting value for this metric’s type. metered ignores this field entirely. boolean takes {"enabled": <bool>}. gauge takes {"cap": <non-negative integer>}. static takes any object, commonly {"config": ...}.

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

metadatarequiredobject

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

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

Errors

  • 409This key already exists for your tenant. A metering rule made earlier for this key can cause this too. Creating a rule for an unknown key makes a plain billable metric on its own. Call getBillableMetric to see what is already there. conflict
  • 422key or name is missing, type is not one of the four values, or default_value does not match type’s shape. A missing Idempotency-Key header returns this too. The response names the field where it can. validation-error

Retrieve a billable metric

GET/v1/billable-metrics/{key}
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 returns one billable metric by its key. The metering rule that prices it is separate — list those, filtered by this same key.

Path parameters
FieldTypeMeaning
keyrequiredstring

The billable metric’s own key, exactly as you sent it to createBillableMetric.

Response 200
{
  "id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a52",
  "key": "chat_message",
  "name": "Chat message",
  "description": "One message sent in a chat session.",
  "status": "active",
  "type": "metered",
  "default_value": {},
  "metadata": {},
  "created_at": "2026-07-20T09:00:00Z",
  "updated_at": "2026-07-20T09:00:00Z"
}
Response fields
FieldTypeMeaning
idrequiredstring (uuid)
tenant_idrequiredstring (uuid)
keyrequiredstring

The name your code sends with each use of this metric, and with its metering rule.

namerequiredstring
descriptionrequiredstring

Longer, free text for dashboards. An empty string unless you set one.

statusrequiredstring

Active or inactive, for your own records. QuotaStack does not use this to block usage today.

  • activeThe normal state for a metric in use.
  • inactiveA label only — checks and usage still work the same way.
typerequiredstring

What kind of entitlement this metric is, and what a check call returns for it. Fixed after creation.

  • meteredPriced by a metering rule and paid for out of the customer’s balance. A check returns the balance and the estimated cost.
  • booleanA plain on/off flag, like SSO access. A check returns {"enabled": true} or {"enabled": false}, and costs nothing.
  • gaugeA count with a cap, like a seat limit. A check returns the cap and how many the customer has used so far.
  • staticA JSON value your app reads directly, like a list of models you allow. A check returns that value only.
default_valuerequiredobject

The starting value for this metric’s type. metered ignores this field entirely. boolean takes {"enabled": <bool>}. gauge takes {"cap": <non-negative integer>}. static takes any object, commonly {"config": ...}.

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

metadatarequiredobject

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

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

Errors

See also

Update a billable metric

PATCH/v1/billable-metrics/{key}
Idempotency-KeyNot required for this operation.
EnvironmentSandbox and Live
AuthTenant API key
WritesApplies the fields you send. metadata and default_value REPLACE the stored object outright — unlike a customer update, neither one merges.
Fires No webhooks.

This endpoint changes one or more fields on an existing billable metric, found by key. Updating one needs an Idempotency-Key header, like every write. openapi.yaml skips it here, but QuotaStack still checks. A field you skip keeps its old value. type cannot change after creation.

Path parameters
FieldTypeMeaning
keyrequiredstring

The billable metric’s own key, exactly as you sent it to createBillableMetric.

Body parameters
FieldTypeMeaning
nameoptionalstring

A label for lists and dashboards.

If you leave it out: The old value stays. QuotaStack changes nothing.

descriptionoptionalstring

Longer, free text for dashboards. Send an empty string to clear it.

If you leave it out: The old value stays. QuotaStack changes nothing.

statusoptionalstring

Marks the metric active or inactive, for your own records. QuotaStack does not use this to block usage today.

If you leave it out: The old value stays. QuotaStack changes nothing.

  • activeThe normal state for a metric in use.
  • inactiveA label only — checks and usage still work the same way.
typeoptionalstring

Must equal the metric’s current type. A different value returns 422. The same value is fine and changes nothing.

If you leave it out: The old value stays. QuotaStack changes nothing.

  • meteredPriced by a metering rule and paid for out of the customer’s balance. A check returns the balance and the estimated cost.
  • booleanA plain on/off flag, like SSO access. A check returns {"enabled": true} or {"enabled": false}, and costs nothing.
  • gaugeA count with a cap, like a seat limit. A check returns the cap and how many the customer has used so far.
  • staticA JSON value your app reads directly, like a list of models you allow. A check returns that value only.
default_valueoptionalobject

The starting value for this metric’s type. metered ignores this field entirely. boolean takes {"enabled": <bool>}. gauge takes {"cap": <non-negative integer>}. static takes any object, commonly {"config": ...}.

If you leave it out: The old value stays. QuotaStack changes nothing. Sending a value REPLACES the stored object outright — it does not merge.

metadataoptionalobject

Your own key-value tags.

If you leave it out: The old value stays. QuotaStack changes nothing. Sending a value REPLACES the whole object outright — it does not merge.

Request
{
  "name": "Chat message (v2)"
}
Response 200
{
  "id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a52",
  "key": "chat_message",
  "name": "Chat message (v2)",
  "description": "One message sent in a chat session.",
  "status": "active",
  "type": "metered",
  "default_value": {},
  "metadata": {},
  "created_at": "2026-07-20T09:00:00Z",
  "updated_at": "2026-07-20T11:00:00Z"
}
Response fields
FieldTypeMeaning
idrequiredstring (uuid)
tenant_idrequiredstring (uuid)
keyrequiredstring

The name your code sends with each use of this metric, and with its metering rule.

namerequiredstring
descriptionrequiredstring

Longer, free text for dashboards. An empty string unless you set one.

statusrequiredstring

Active or inactive, for your own records. QuotaStack does not use this to block usage today.

  • activeThe normal state for a metric in use.
  • inactiveA label only — checks and usage still work the same way.
typerequiredstring

What kind of entitlement this metric is, and what a check call returns for it. Fixed after creation.

  • meteredPriced by a metering rule and paid for out of the customer’s balance. A check returns the balance and the estimated cost.
  • booleanA plain on/off flag, like SSO access. A check returns {"enabled": true} or {"enabled": false}, and costs nothing.
  • gaugeA count with a cap, like a seat limit. A check returns the cap and how many the customer has used so far.
  • staticA JSON value your app reads directly, like a list of models you allow. A check returns that value only.
default_valuerequiredobject

The starting value for this metric’s type. metered ignores this field entirely. boolean takes {"enabled": <bool>}. gauge takes {"cap": <non-negative integer>}. static takes any object, commonly {"config": ...}.

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

metadatarequiredobject

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

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

Errors

  • 404No billable metric here has this key. not-found
  • 422type does not match the metric’s current type, status is not active or inactive, or default_value does not match type’s shape. A missing Idempotency-Key header returns this too. Sending the metric’s own current type back is fine and changes nothing. validation-error

See also