Pricing JSON

Pricing models are expressed as a single JSON object.

This document describes the structure of a pricing.json file, and the behavior that each option implies. It is intended to be a comprehensive reference.

If you're getting started, or just want to see some examples, please check out the Recipes to see examples of pricing.json files reflecting common SaaS pricing models.

JSON Schema

A JSON schema for pricing.json can be found at https://www.tier.run/docs/pricing.schema.json.

Plans

The root object in a pricing.json contains a plans object.

Each key in the plans object is a versioned plan name starting with plan:. The values are plan definitions.

For example:

{
"plans": {
"plan:basic@0": {
"title": "Just a basic plan",
"features": {
"feature:foo": {
"tiers": []
}
}
}
}
}

Note that we must put at least one feature in the plan, or else tier will not accept it.

Once pushed, a plan may not be modified or deleted. A new version of the plan may be added, however:

{
"plans": {
"plan:basic@0": {
"title": "Just a basic plan",
"features": {
"feature:message": {}
}
},
"plan:basic@1": {
"title": "A new version of the plan"
"features": {
"feature:message": {}
}
}
}
}

Plan Objects

Each of the values in the plans collection are plan objects.

title

A plan may contain a title field, which must be a string if provided. This serves as a human-readable description of the plan for invoices and other content. If no title is provided, then the plan ID is used instead.

interval

This is a string specifying the billing interval for the feature. It must be one of the following values:

currency

This is a string specifying the currency that features are priced in. Default is "usd".

features

The features field is an object containing all of the features enabled by this plan. The keys in the features field are feature names starting with feature:. The values are feature objects.

{
"plans": {
"plan:basic@2": {
"title": "Now with features!",
"features": {
"feature:message": {
"tiers": [{ "upto": 10, "price": 0 }]
}
}
}
}
}

Feature Objects

A feature object describes the pricing of a feature within the context of a plan.

A feature object may contain the following fields:

mode

This is a string specifying how to determine a bill for a feature using "tiers".

For example:

{
"plans": {
"plan:mode-example@123": {
"feature:volume": {
"mode": "volume",
"tiers": [
{ "upto": 10, "price": 2 },
{ "price": 1 }
],
},
"feature:graduated": {
"mode": "graduated",
"tiers": [
{ "upto": 10, "price": 2 },
{ "price": 1 }
],
}
}
}
}

If a customer on this plan consumed 10 units of either the feature:graduated or feature:volume feature, the price would be the same, because all usage falls within the first tier.

However, if the customer consumed 15 units of both, then the price for feature:graduated would be:

v--- first tier usage and price
(10 * 2) + (5 * 1) = 25  <-- total
           ^--- second tier usage and price

However, their price for 15 units of the feature:volume feature would be:

v--- total usage
15 * 1 = 15  <-- total
     ^-- price of final tier reached

aggregate

This is a string specifying the function used to determine the usage multiplier for calculating the total price at billing time. It may only be set on features that include tiers.

This maps directly to Stripe's aggregate_usage field.

base

The base field is a positive integer specifying the base price for features without tiers. It is an error to specify both the base field and a non-empty tiers.

tiers

An optional array of tier objects to specify usage-based price tiers. If the feature has a top-level base field, then this is not allowed.

{
"plans": {
"plan:basic@3": {
"title": "Now with *enabled* features!",
"features": {
"feature:message": {
"tiers": [ { "price": "1" } ]
}
}
}
}
}

An empty tiers array means that users on this plan are not entitled any usage of the feature.

Tier Objects

Each tier may include the following fields:

upto

This is a positive integer specifying the maximum usage amount for this tier.

If not specified, the default is an unbounded tier (that is, infinite).

price

This is an integer specifying the per-unit price for any usage that occurs within this tier.

If not specified, the default is 0.

base

This is an integer specifying flat price for any usage that occurs within this tier.

If not specified, the default is 0.

Example

{
"plans": {
"plan:free@0": {
"title": "Todo (Free)",
"features": {
"feature:todo:lists": {
"tiers": [
{
"upto": 5
}
]
}
}
},
"plan:pro@0": {
"title": "Todo (Pro)",
"features": {
"feature:support:email": {
"base": 9900
},
"feature:todo:lists": {
"tiers": [
{
"upto": 100
}
]
}
}
}
}
}

Why Each Plan Must Have At Least One Feature

Due to the way that Stripe defines Products and Prices, and the fact that Tier endeavors to make everything as safely immutable as possible, every plan in your pricing.json must have at least one feature defined.

Without this restriction, it would be significantly more expensive to fetch your pricing model from Stripe's data.

We aren't aware of any use cases where you'd want to have customers subscribed to plans that don't grant them access to any features (since that would be equivalent to not being subscribed to any plan at all!), but if you need this for your application, definitely let us know!