tierrun / tier

The easiest way to add pricing to your SaaS. Get billing over with.
https://tier.run
BSD 3-Clause "New" or "Revised" License
964 stars 32 forks source link

FR: native support of credit based billing #170

Open jevon opened 2 years ago

jevon commented 2 years ago

What are you trying to do?

Some vendors prefer to use a credit based approach to billing. This is especially useful when they are reselling some underlying service.

Examples include:

In these examples, you pay a monthly fee for some bucket of usage you can draw from. At the end of the month, unused capacity/credit expires.

Starter Boss Mode
Words Per Month 20,000 Words 50,000 Words
Users 5 5

How should we solve this?

It may be possible to solve some of these use cases using existing tiering. In a post-paid scenario they act just like any other consumption based billing.

For pre-purchased credits, I'm not sure how to implement it using our existing feature plans.

What is the impact of not solving this?

Certain users may not be able to implement their preferred billing model.

Anything else?

There seems to be a wide variety of approaches to using credits. They are used standalone often, but it seems they are mostly used in combination with other models (seat based or other packages of features).

isaacs commented 2 years ago

Some thoughts on how we could address this with the model we have currently.

All of these feel a bit like a square-peg-round-hole, but maybe could be workarounds or the start of a solution.


  1. Vendor tracks the credits.

In this model, the vendor keeps track of how many credits each org has in their balance, for the "straight credits purchase" approach. Tier doesn't put anything about their current balance anywhere, and they get invoiced at the end of the month for any credits purchased that month.

{
  "plans": {
    "plan:basic@0": {
      "features": {
        "feature:credit:purchase": {
          "tiers": [{"price": 100}]
        }
      }
    }
  }
}

Vendor calls tier.report(org, 'feature:credit:purchase', 1) any time a credit is purchased, and tracks how many they have left and how many they spend.

  1. Same as (1), but tier tracks the balance. We have a zero-cost feature that's just the balance and they report the increase/decrease, and use tier.limit() to get the balance.
{
  "plans": {
    "plan:basic@0": {
      "features": {
        "feature:credit:purchase": {
          "tiers": [{"price": 100}]
        },
        "feature:credit:balance": {
          "aggregate": "perpetual",
          "tiers": [{"price": 0}]
        }
      }
    }
  }
}

Vendor calls tier.report(org, 'feature:credit:purchase', 1); tier.report(org, 'feature:credit:balance', 1) when a credit is purchased, calls tier.report(org, 'feature:credit:balance', -1) when a credit is consumed, and tier.limit(org, 'feature:credit:balance') to check the balance.

  1. Base credits plus addons

This is how you might say "plan is $50/month for 100 (expiring) credits, additional credits purchasable at $10 for 10 credits (ie, $1 each)".

{
  "plans": {
    "plan:basic@0": {
      "features": {
        "feature:credit:use": {
          "base": 5000
          "tiers": [{ "upto": 100 }]
        },
        "feature:credit:add": {
          "tiers": [{"price": 100}]
        }
      }
    }
  }
}

Then the vendor would check tier.limit(org, 'feature:credit:use') to see if they have credits available, and if not, check tier.limit(org, 'feature:credit:add') usage amount and do some math to figure out how soft the limit should be. So the actual hard cap is feature:credit:use limit + feature:credit:add usage.

If they're below that amount, then the customer has to purchase more credits: tier.report(org, 'feature:credit:add', 10).


What I'd really like, as a vendor, is to somehow have a feature that adjusts the limit of some other feature on the plan when purchased, and have that all expressed outside the app (because all 3 of these scenarios involve pricing logic living in the app, which we don't want).