Model

The "model" is a JSON representation of the plans you define for your application. Each plan contains a set of features, with the tiers defined for usage within that plan. If a plan doesn't include a feature, then that means users on that plan don't have access to that feature.

{
  "plans": {
    "plan:free@1": {
      "features": {
        "feature:song-stream": {
          "tiers": [
            // $1 each stream, but capped at 100 streams/month
            { "price": 100, "upto": 100 }
            // no tiers after this one means no more usage
          ]
        }
      }
    },
    "plan:pro@1": {
      "features": {
        "feature:song-stream": {
          "tiers": [
            // first 200 cost $0.50 each, but $10 up front
            { "price": 50, "upto": 200, "base": 1000 },
            // streams 201-1000 cost $0.10 each
            { "price": 10, "upto": 1000 },
            // then they're free
            {},
          ]
        },
        "feature:song-download": {
          "tiers": [
            // using downloads at all costs $10, but
            // no charge other than the base price
            { "base": 1000 }
          ]
        }
      }
    }
  }
}

Table of Contents

Plans

Every billing plan that a user might be signed up for is identified with a string starting with 'plan:', and containing a @. The part before the @ is the "name". The part after the @ is the "version".

You can define as many versions of as many plans as you want in your pricing model. However, you may not change a given version of a plan, so to make changes you will create a new version of it. This makes it possible to experiment safely with pricing changes, and only update existing customers' plans when it makes sense for your application.

Think of your set of plans as an append-only set of the various ways you package your application and bill your customers.

Append-Only

The goal of Tier is to enable iteration on your pricing structure, in a way that is easy, reliable, and safe.

One of the hardest pieces of any pricing change in a SaaS product is dealing with users who signed up for legacy pricing plans. If their price goes up, you may need to apply discounts to all legacy users to keep them happy, or add custom logic throughout your application to continue to give them access to features they've paid for.

If a certain user negotiates a special price for some reason (special volume discounts for large enterprise customers, for example), then this gets even more complicated, and the risk of losing the customer can be even greater.

Each plan in the Tier model has a name and a version. In order to prevent changing the behavior of an existing user's plan, Tier will not allow you to modify a plan version once it exists. However, if you add a new version of a plan, then that can become the default for new users signing up for your service.

Features

Every feature in your application is identified with a string starting with feature:. The rest of the string can contain any arbitrary identifier that you use internally to reference a feature. You can think of this as a feature flag for restricting usage to paid features and tracking how much of something a customer has consumed.

The feature name should identify what thing the user is trying to do or consume, which you might bill for (or at least track). For example:

The value of a feature object in the model can have the following fields:

Tiers

Each feature has a set of 0 or more "tiers", which define the prices and limits for use of that feature. Each tier has the following fields:

The simplest "free, unlimited" tier is {}. Since it doesn't specify anything, it uses the defaults: up to Infinity, $0.00 per unit, $0.00 base price.

For example, if we want to say that streaming a song on our platform costs $1 each for the first 100, and then $0.50 thereafter, we could do:

{
  "plans": {
    "plan:streamer@123": {
      "features": {
        "feature:song-stream": {
          "tiers": [
            // $1 for the first 100
            { "price": 100, "upto": 100 },
            // $0.50 thereafter
            { "price": 50 }
          ]
        }
      }
    }
  }
}

A feature with no tiers means that users on the plan are not entitled to that feature.

{
  "plans": {
    "plan:streamer@123": {
      "features": {
        "feature:song-stream": {
          "tiers": [{ "price": 100, "upto": 100 }, { "price": 50 }]
        },
        // Explicitly disabled. Any usage will be treated as overage.
        "features:song-download": {
          "tiers": []
        }
      }
    }
  }
}

Pushing a Model

Create your model in any filename that you prefer. We typically use pricing.json.

Push the pricing model from the command line by installing one of the Tier SDKs and then running:

tier push pricing.json

In the background, this is just making a request to the Tier API. You can also send it programmatically by using the tier.pushModel(<filename>) function in the SDK, or by making an http request using your tool of choice:

curl -X POST \
  -u $TIER_KEY: \
  -H "Content-Type: application/json" \
  -d $(cat pricing.json)