Build any Pricing and Billing Model (Price Machine)
At the core of our Billing Cloud, built from the ground up to tackle the demands of real-time usage-based pricing and billing, is a highly flexible and scalable Pricing Machine State Engine (a.k.a rating engine).
We describe below some of the artifacts and how the pricing machine works. This background will help you understand the unique and powerful capabilities and flexibility of the pricing engine and, we hope, will unleash your imagination in building and deploying the pricing models that best suit your products and customer base.
It provides the tools needed to create any pricing plan that you have in mind.
Before delving into the different types of price machine nodes, we will provide a high-level description for how the price calculation works.
Amberflo invoice calculator is the logic which converts a specific meter's hourly usage aggregation for a given customer to an invoice.
The exact input which the invoice calculator consumes is the meter hourly usage aggregation of a given customer partitioned by all of the official dimensions of the invoice.
Then the price calculator executes the following steps: Step 1: Fetch the relevant price machine for the customer and the meter. Step 2: Reduce the input to a smaller set of partitions as defined by the specific price machine. Step 3: Execute the price machine on the reduce input.
The exact output of the price machine is set of what call an 'Item-Variant-Invoice'. An 'Item-Variant-Invoice' is a partition of the invoice by a sub-set of the meter official dimensions.
Given these we will define each price machine using two properties:
- Required dimensions
- Function
Let's assume you have the following meter:
Then the price machine will create the following 'Item-Variant-Invoice':
Now that we know something about how Amberflo's price machine works, we will introduce the different types of machines we offer.
The leaf price machine is the simplest price machine one can think of, and yet as we will see next it by itself quite an advance price machine.
The properties of this machine are:
- Required dimensions : none
- Function : tier based price step function.
Bellow is the 'leaf price machine' schema:
Unless you want to partition the invoice by a subset of the meter dimensions then this machine is likely all you need.
Let's look at a few examples of possible configuration for this machine.
A machine that calculates a price of $0.10 per 1 unit of usage.
For example the price of 12 units of usage is $1.20.
A machine that calculates a price of $0.50 per 5 units of usage with no partial batching.
Unlike the previous example this machine doesn't allow partial batches, which means, the price usage will be rounded up to whole unit of the batch size, and the price will be determined based on the amount of batches.
For example, the price of 12 units of usage is $1.50 (3 batches).
A machine that calculates a price of $0.10 per each 1 unit of usage for the first 10 units of usage, and then drop the price to $0.05 for each unit afterwards.
For example, the price of 12 units of usage is $1.10 (0.1 10 + 0.05 2).
A machine that calculates a price of $0 per each 1 unit of usage for the first 10 units of usage, and then increases the price to $0.05 for each unit thereafter.
For example, the price of 12 units of usage is $0.1 (0 10 + 0.05 2).
Discrete-price-leaf-node is another type of a leaf node. It is different than the Price-leaf-node in a way that it calculates the price of each usage time slot independently of other hours.
For example: Let's assume we have the following tiers:
- 0-100: no charge
- 100 or more: $1 per 1 unit of usage.
Now let's assume we had the following usage:
- day 1: 95
- day 2: 75
With the original Price-leaf-node we will charge that customer for $70 (95 + 75 - 100). This is because the that model applies the tiers for the usage over the entire period.
With this Discrete-price-leaf-node we will charge the customer for $0 because on each day we used less than 100 units.
The properties of this machine are:
- Required dimensions: none
- Function: tier based price step function.
Bellow is the 'discrete leaf price machine' schema:
A leaf node can calc the price of a given usage (of a given invoice-variant) without deferring any pricing decisions to subsequent nodes. In other words a leaf node can't have subsequent nodes which it depends on.
For this leaf-node the only thing that dictates the price of a meter is the total amount of usage over time.
This price node is based on the total usage volume. For example, Let's assume we have the following tiers:
- from 0 -> $1 per unit of usage
- from 10 -> $3 per unit of usage
Example: let's assume that during an invoice cycle we have a total of 15 units used. Then the price should be: 15 * 3 = $45
The properties of this machine are:
- Required dimensions: none
- Function: tier based price function (but not a step function).
Bellow is the 'Volume based leaf leaf ' schema:
Example:
In the example above we describe the following tiers table:
- from 0 -> $1 per unit of usage
- from 10 -> $3 per unit of usage
And to calculate the price of 15 units of usage we just multiple 15 by 3 = $45.
But what if the values were decreasing as the usage goes ?
For example let's assume we have the following table:
- from 0 -> $3 per unit of usage
- from 10 -> $1 per unit of usage
Now, a customer with 15 unit of usage will pay $15, while a customer with 9 unit of usage will pay 9 * 3 = $27. That stands against the core ideas of "usage-based-pricing", that guide us to create fair price machines (where if you use more you pay more, and there is no reason to use the system more just to pay less).
So, one by design limitation of this price-machine is that the price per unit can only increase as we use the system more. If you wish to let it decrease then please refer to the 'price-leaf-node' and 'discrete-price-lead-node' mentioned above.
This type of machine allows you to create a different price logic for different combinations of dimensions values.
Basically you define a Price-Leaf-Node for each combination of dimensions values. Notice that this price machine will drop any usage for which the dimension values are not defined in the price machine (we will share an example for this below).
The properties of this machine are:
- Required dimensions: as defined in the 'dimensionKeys' property.
- Function: A sum of a tier based price step functions.
The machine below defines a price according to the following pricing plan:
Equivalent price machine:
This machine counts the distinct values for a subset of dimensions and then calculates a price using a Price-Leaf-Node for the count.
The distinct values count function can be applied on:
- Each individual hour.
- Each day.
- For the entire invoice period.
The properties of this machine are:
- Required dimensions: as defined in the 'resourceDefiningDimensions' property.
- Function: A sum of a tier based price step functions which is applied on the result of the distinct count.
Let's assume your company has a pool of machines and provides a service which allows your customers to use your machines to run all kind of tasks on-demand.
Let's also assume that you measure how long each task runs, but for simplicity you want to invoice customers by the distinct number of tasks that they run during the invoice period. In such a case you can define the following price machine:
This machine will have a distinct count for all of the jobs that ran during the invoice-period (regardless of how long they ran or if the runtime was spread over multiple hours or days), and charge the customer $2 per each batch of 5 jobs.
Similarly to the 'Distinct-Resource-Reducer' this price machine node can also reduce the time granularity of your hourly usage. This price machine finds the max value to pick the value of each usage partition.
This model allows you to charge your customers based on the peak hourly usage over:
- Each day.
- The entire invoice period.
The properties of this machine are:
- Required dimensions: Inherit the 'Required dimensions' of the next node.
- Function: apply the next node function over the hourly, daily or entire_invoice max usage.
NOTICE: you can plug this price-machine-node to any of the price machines described above.
Let's use the previously mentioned example and assume your company has a pool of machines and provides a service that allows your customers to use your machines to run all kind of tasks.
But this time, let's assume you want to charge your customers according to the max hourly usage rate they incurred during the invoice period.
You can create a map_reducer similar to that described below.
Let's assume we take Example 2, mentioned above (for the dimensions matrix), but this time we want to calculate based on the max daily value.
As mentioned, we can have any node as the next node of the max_reducer price machine. Therefore we can just wrap the aforementioned 'DimensionMatrixNode' inside of a max_reducer.
This node has a similar logic to the "Max Reducer" described above with two main differences:
- It calculated the avg usage instead of a max - although notice that similarly to the "Max Reducer" we can split the usage into hours (hourly avg), days (an avg value for each day of the invoice), or calc one avg value for the entire invoice period.
- The avg is being calculated over the ORIGINAL time period of invoice.
Regarding #2:
Avg is calculated using the following formula:
Now, let's look at the following example and ask ourselves what is the denominator, meaning what are the t2, and t1 values.
- Let’s assume today is 7/22/2022.
- We started an invoice at 7/15/2022.
- The end time of the invoice is 8/15/2022
To make things simple let's assume our avg price state machine granularity is 'entire_invoice_period':
So, at 7/22 we have two options for how to calc the denominator: Option 1 - from 7/15/2022 to 7/22/2022, using current usage Option 2 - from 7/15/2022 to 8/15/2022, using current usage
When we said that the avg is being calculated over the ORIGINAL time period of invoice we meant is that we follow option 2. Option 2, has some big advantages over option 1 among them are:
- Using option 2 the price only goes up and can't really fluctuate.
- Option 2 is a more fair pricing mechanism for scenarios where a customer changes it plan or offboards from a service.
The main reason to use this node is if you want to partition your usage by a certain set of dimension values which is not included in the next nodes, without specifying a unique leaf-price machine as done in the dimensions-matrix-node.
For example, let's assume you operate on many regions but you have the same pricing logic for all regions. Having said that, let's assume that when generating the invoice you want to calculate the price-per-region using the same leaf-node. You can use this method to have such logic.
The properties of this machine are:
- Required dimensions: A unified set as defined in 'resourceDefiningDimensions' + the 'Required dimensions' of the next node.
- Function: apply the next node function over the partitioned usage.
We can implement the example mentioned above (partition by region but keep the same price logic for all regions) using a configuration similar to the one below:
Two ways to define a price machine:
- Via Amberflo's console - Amberflo's console contains a wizard that allows you to define most of the models mentioned above. It's an easy and safe way to do it.
- If the UI doesn't support the exact configuration you want to have then you can always use our APIs. The URL is: http://app.amberflo.io/payments/pricing/amberflo/account-pricing/product-item-price(just notice that the price-machine is one attribute of the entire item-price object - example )