Tier Basic Concepts

This guide covers the basic concepts that Tier uses. If you're just getting started with Tier, and want to skip all this, check out the Getting Started with Tier guide as well.

Table of Contents

Orgs

Every customer of your application is identified to tier by a string starting with 'org:'. The rest of the string can contain any arbitrary identifier that you use internally to reference the customer.

These are all valid OrgName values:

The important thing is that you can link the org to an actual user within your app, so that you always send the same OrgName for the same actual customer.

Read more about orgs

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:

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": []
        }
      }
    }
  }
}

Plan

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.

Schedules and Phases

Each org can be put on a given plan:<name>@<version> by calling tier.appendPhase(org, plan). This appends a new phase to their billing schedule. The current active phase determines how much they will be charged for their usage, and what features they are entitled to use.

A user will be invoiced based on the phase in which their usage occurs.

An org must be given a plan before you can track usage for it. Until then, any feature check you try to make for that org will fail. (They haven't signed up for your service, so they can't use any paid features!)

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 }
          ]
        }
      }
    }
  }
}

Read more about Pricing Models

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)

Tracking and Recording Usage

Feature usage can be checked by calling tierClient.can(), and reported using tierClient.report().

In general, if can() returns false, then the user is over the limit or doesn't have access to the feature in their plan, so you should not give them the feature.

report() can be called right away, ahead of delivering the feature, or at any arbitrary time.

For example:

if (await tier.can('org:acme', 'feature:foo')) {
  consumeOneFoo('acme')
  await tier.report('org:acme', 'feature:foo')
} else {
  // suggest they buy a bigger plan, maybe?
  showUpgradePlanUX('acme')
}

Read more about Usage