This is the reference guide to get started with Kill Bill Subscription Billing.
Introduction
Kill Bill, as a system, is composed of several components:
-
The core billing platform itself, which is embedded in a web server and offers a REST api. When we refer to Kill Bill in the documentation, this is what we are referring to, unless explicitly specified
-
KAUI, the Kill Bill Admin UI, which is a Rails mountable engine, and communicates with the core billing platform using the REST api
-
A set of client libraries (Java, Ruby, PHP, Node.js, …)
Let’s consider some common web-based use cases for Kill Bill. Each of these cases combines Kill Bill with custom code to implement the specific business logic required. Kill Bill solves the billing problem but not the custom flow required around the billing platform. This must be handled by the custom code, which should support the following functions:
-
Offer a way for customers to select a plan from the Kill Bill catalog, which would result in the creation of a subscription
-
Offer a form for customers to enter their payment information, using a credit card or any other payment method. The flow will differ depending on the payment gateway and PCI compliance needs
-
Offer a way for customers to review and change their subscriptions
-
Offer a way for customers to review and change their payment methods
The first option is to create a custom web app, containing the application-specific business logic, that interacts with Kill Bill using the REST API.
The second option is to embed the application-specific code inside Kill Bill. In this case no separate app is required.
The final option would be to create a custom web app and embed Kill Bill into it. Kill Bill offers a set of Java APIs below the REST API, so it is possible to use Kill Bill as a billing library.
Preliminary Requirements
Before beginning this guide, you should perform the following preliminary steps:
-
Review the Getting started tutorial.
-
Using the tutorial, get MySQL, Kill Bill and Kaui set up and running in Docker containers.
-
Set up a tenant configured with API key
bob
and API secretlazar
. -
Ensure that you have cURL installed. This is only to be able to run the setup steps and examples from this documentation. In practice, your application will use one of our client libraries. If you are on Windows, we recommend that you use Git Bash to run the
cURL
commands.
Catalog
Overview
The catalog is the central configuration object of Kill Bill for all of your Business rules. It contains what the customer buys (products), how the customer pays for a product (plans), change rules, prices, etc.
In practice, the catalog is an XML file: here is a basic example we use in most of our tests and tutorials. We also have a few other examples to get you started here.
Please refer to the Catalog Configuration documentation to make Kill Bill use your own catalog.
The catalog is one of the most complex yet powerful tools provided by Kill Bill.
If you want to validate your catalog, you can use the catalog load-tool (where x.y.z is your current Kill Bill version):
# Download the tool from maven central:
curl -L -O 'http://search.maven.org/remotecontent?filepath=org/kill-bill/billing/killbill-catalog/x.y.z/killbill-catalog-x.y.z-load-tool.jar'
# Run the command
java -jar killbill-catalog-*-load-tool.jar /path/to/catalog.xml
If you see "Success: Catalog loads!", the catalog is valid.
Also, if you need an xsd file, you can find one here or generate one using the catalog xsd-tool:
# Download the tool from maven central:
curl -L -O 'http://search.maven.org/remotecontent?filepath=org/kill-bill/billing/killbill-catalog/x.y.z/killbill-catalog-x.y.z-xsd-tool.jar'
# Run the command
java -jar killbill-catalog-*-xsd-tool.jar schema.xsd
Introduction
The Catalog is a data model that captures the core configuration of the billing system. This model is at the heart of the billing system. It is very important that all the business logic associated with the billing behaviour of your system is captured in the billing system. If your billing system is not capable of capturing all of the business logic it ends up being put in multiple places such as your purchase flow, Admin UI, human process etc. It becomes very difficult to keep all these places consistent, and very difficult to make changes when they are needed.
Kill Bill provides a very powerful catalog that, unlike other billing systems, allows the administrator to set up sophisticated business rules around cancellation and plan changes. For example, Kill Bill can just be told to “Cancel” a plan and it will know when to perform the cancel, based on things like the type of plan, or whether it is in trial.
The things you can configure with the Kill Bill catalog include:
-
Trials and discount phases - plans can be configured with trial and discount phases so that they move automatically between different pricing schemes
-
Cancellation - business rules to determine when a cancellation should happen.
-
Plan Change - business rules to determine when to apply upgrades and downgrades.
-
Which add-ons are available with which product types, so that when the customer upgrades or downgrades, add-ons that are not available are automatically cancelled
-
Billing Alignment - rules to determine if a Plan should be billed independently or on the account billing date.
-
Catalog change - ways to specify how and when catalog changes apply to new and existing subscriptions
Kill Bill also supports the concept of a Price List, which is a grouping of (usually discounted) plans that can be offered to a customer.
Of course, any catalog can only support a limited number of options. When you need to go further, and many people do, you can write plugins to implement pretty much anything you need.
Concepts
In this section we outline some key pieces of terminology that you will need to understand. A complete Glossary is given at the end of this document. Different billing systems use these same words to mean subtly different things so, even if you are familiar with the language, it is worth looking through exactly how we use the terms in Kill Bill.
Background Concepts
-
Customer – someone who buys your product
-
Administrator (or Admin) – the person who can use the Kill Bill UI to view and modify customer accounts
-
Kill Bill Administrator (or Kill Bill Admin) - the person responsible for installing or configuring Kill Bill
-
Account – a customer account. It represents what Kill Bill knows about a customer.
-
Subscription – a contract between you and a customer to purchase a particular product with particular terms. In the system it associates a Plan (see below) with an Account and a start date.
-
Subscription Bundle (or just Bundle) – a collection of subscriptions that are associated with a particular instance of a product. For example, you might have a voice plan, a data plan and a text plan for your mobile phone. In Kill Bill each plan would have its own subscription and we would represent the fact that they are associated with a single phone by grouping them in a Subscription Bundle. Of course an account might have multiple phones associated with it and a Kill Bill Account can have multiple Bundles associated with it.
What’s in a Catalog?
A Kill Bill Catalog includes the following sections:
-
Products - The things that the customer actually buys (or rents). In the example depicted at the start of the chapter, the product available for rent is a Spy Car, which is available in three different versions:
Standard
,Sports
andSuper
. -
Plans - Specifications for the terms of the Subscription contract. In particular, plans define how much a customer pays for a product, and how often they pay it. For example, we could offer the Standard Spy Car product at $100 per month.
-
Plan Phases (or just Phases) - Time periods within a subscription during which certain rules apply. Kill Bill plans can have multiple phases and each phase can have a different price and payment term. In this way, we can have plans with built in trials or discount phases. Kill Bill automatically handles the transitions between phases. In our example above the plans have two phases: they start with a 30 day trial which is free, and then move to a recurring phase at $100 per month.
-
Price List - A collection of plans. Price Lists are normally used to group discount plans that are associated with a particular customer group. For example, MI6 might have special rental terms for their Spy Cars with the CIA. In this case they would create a CIA Price List that grouped plans with those special terms together. When CIA agents would come to the rental site, they would see plans from that price list. More importantly, if they change plans (for example, if they upgrade from Sports to Super to meet the needs of a particularly difficult mission), they will upgrade to the Sports plan within the CIA Price List.
-
Billing Period - The period for which the customer is billed (e.g
MONTHLY
,ANNUAL
, …) -
Rules - The rules that determine how Kill Bill should behave when a plan is created, cancelled or changed.
How is the Catalog Used Inside Kill Bill?
Kill Bill first uses the catalog when the user creates a subscription, then subsequently if there is a change of Plan
(upgrade or downgrade), and then finally when the user cancels the subscription. During such operations, catalog information is retrieved to make sure the system builds the right subscription (e.g. maybe there is a TRIAL
phase to start). Information about how to perform such operations is configured in the catalog through the Subscription Alignment Rules. Examples of these rules include:
-
Plan Cancellation Timing - Should the customer get a pro-ration credit when the subscription is cancelled before its next renewal date?
-
Plan Change Timing - Should a customer downgrading to a lower (paid) plan be active immediately or should the system wait for the next renewal date?
The catalog is also used by the invoicing system to make sure each customer is billed at the right time and for the right amount. Information about how the customer is billed and when the customer is billed is also defined in the catalog using alignments and their associated rules.
Catalog configuration allows the Kill Bill Administrator to define whether all subscriptions attached to a customer should be invoiced at the same time, or if they should be billed separately on their own schedule. There could also be a mix of both where some are grouped together on the same invoice and others are invoiced independently. In the simplest case, the customer gets one invoice per billing period. Note that grouping subscriptions together may by default lead to some proration for a new subscription, to align it with the billing period. For further discussion of this topic see Billing Alignment Rules.
Creating the Catalog
Most Kill Bill catalogs have the form of XML documents. Complex catalogs may need to be created by Java programs using a custom plugin (see Developing a Catalog Plugin), while simple catalogs can be generated directly by the Kaui interface (see the Kaui Catalog Interface). This section describes how to create a catalog configured to your particular needs. For this discussion we assume the catalog is an XML document.
The XML document starts in a standard way. The main tag is <catalog>
. Within the catalog
tag you should specify the schema location.
You can use the standard schema location, as shown in the example. This schema can be found at XSD schema.
In most cases this schema will meet your needs. If not you can have the code generate the current schema by executing the tool killbill-catalog-x.y.z-xsd-tool.jar, where x.y.z
is replaced by the appropriate version of Kill Bill. The tool for version 0.22.0
can be found here. After downloading this tool, the schema can be generated by the following command:
java -jar killbill-catalog-x.y.z-xsd-tool.jar <output_filename>
The order of content information in the catalog is important. The first tag should be the “effectiveDate” (when the catalog becomes effective), then “catalogName” and then “currencies”, as shown below. Further, the catalog requires all attribute strings to be unique, and those strings cannot contain spaces.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://docs.killbill.io/latest/catalog.xsd">
<effectiveDate>2013-02-08T00:00:00+00:00</effectiveDate>
<catalogName>SpyCarBasic</catalogName>
<currencies>
<currency>USD</currency>
<currency>GBP</currency>
</currencies>
...
</catalog>
We have now described the heading information for the catalog. The following discussions explain in depth the catalog sections that correspond to the concepts described above.
Products
The Product is a representation of the thing the customer is actually buying. Specifying a Product is very straightforward. The product is described by the following parameters:
-
Name - a string that is used to refer to the Product elsewhere in the catalog. For example "Super".
-
Category - a descriptor that determines how Kill Bill allows the combining of this product with others within a bundle. The options are BASE, ADD_ON and STANDALONE. These options are explained below.
-
Inclusion/Exclusion lists (optional) - Lists that determine which addons can be purchased with a given base plan.
Plans
Plans specify the terms of a subscription contract. Each Plan has a name and refers to the purchase of a single product. The details of a Plan are arranged by phase. In the illustration (right) we are showing a Plan with a 30 day Trial followed by an unlimited recurring or "evergreen" phase.
For each phase of the Plan we need to specify:
-
Phase Type - can be one of TRIAL, DISCOUNT, FIXEDTERM, EVERGREEN
-
Duration - the length of the phase in days, months, years or UNLIMITED
-
Billing Period - how frequently do we want to invoice for this phase. Can be DAILY, WEEKLY, BIWEEKLY, THIRTY_DAYS, MONTHLY, QUARTERLY, BIANNUAL, ANNUAL, BIENNIAL or NO_BILLING_PERIOD
-
Recurring Price - the recurring price that needs to be paid every billing period (unless no billing period was specified). The price needs to specify numeric values for every currency that the catalog supports.
-
Fixed Price - a fixed price charged at the beginning of the period in addition to the recurring price. This is also a multi currency price and must be specified for all currencies.
-
Usage Sections - these are optional and outside the scope of this tutorial.
Plan, Phase and Usage sections can have a prettyName
element which would correspond to the display name (such information is subsequently available on invoice items). This is useful for instance if a product is rebranded to a new name in a subsequent version. Plan names don’t need to be updated.
Note that unlike prettyName
, the name
elements need to be globally unique in the catalog and must conform to the XML NCName
definition. This means that they cannot contain symbol characters like :, @, $, %, &, /, +, ,, ;,
, whitespace characters or parentheses, and they cannot begin with a number, dot or minus character.
For our Spy Car catalog example we specify three plans with two phases:
-
The first phase is of type TRIAL and it has a duration of 30 days and a Billing Period set to "NO_BILLING_PERIOD". There is no recurring price specified, and the fixed price is given as £0/$0.
-
The second phase is of type EVERGREEN. It has a Duration of UNLIMITED, a Billing Period of MONTHLY, and a recurring price of £75/$100 (or whatever is appropriate for the Product).
<plans>
<plan name="standard-monthly">
<product>Standard</product>
<initialPhases>
<phase type="TRIAL">
<duration>
<unit>DAYS</unit>
<number>30</number>
</duration>
<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
<fixedPrice> <!-- empty price implies $0 -->
</fixedPrice>
</phase>
</initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
</duration>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price>
<currency>GBP</currency>
<value>75.00</value>
</price>
<price>
<currency>USD</currency>
<value>100.00</value>
</price>
</recurringPrice>
</finalPhase>
</plan>
...
</plans>
Product Categories
As noted above, Kill Bill supports three categories of products:
-
Base Products - Products that can have one or more addons
-
Add-On Products - Products that can be bundled with a base product
-
Standalone Products - Products that cannot have any addons
The terms BASE, ADD_ON, and STANDALONE represent plans that are associated with these three types of product respectively. Having an explicit representation of Add-On products allows Kill Bill to be configured to only allow purchases of add-ons with particular base plans, and to trigger appropriate cancellations automatically when the base plan changes or is cancelled.
A Subscription Bundle is a collection of subscriptions that correspond to an individual product instance, such as all the subscriptions associated with a single cell phone, or, in our example catalog, all the subscriptions associated with the rental of a Spy Car. Subscription Bundles can either consist of a collection of subscriptions to stand-alone plans or a single Base Plan subscription with zero or more Add-On Plan subscriptions.
The Kill Bill catalog allows you to specify the inclusion and availability of Add-On Products with associated Base Products. For example, suppose that we create some add-on products for our example catalog. Let’s add an OilSlick
Product and a RemoteControl
Product. Now, let’s discuss the availability and inclusion of these:
-
Neither product is available in the
Standard
Plan, meaning that you can’t purchase either of these add-ons if you are onStandard
. -
Both products are available on the
Sport
Plan. -
RemoteControl is available on the
Super
Plan, but as we can see from the original Plan definition,OilSlick
is already included in theSuper
Plan.
If we have this specified in the catalog then Kill Bill knows to disallow certain purchases, e.g. it will not allow the purchase of an OilSlick
add-on in a Bundle with a Standard
Base Plan.
Similarly if the Base Plan in a Bundle containing Super
and RemoteControl
is downgraded to Standard
, Kill Bill knows to automatically cancel the RemoteControl
Add-On since it is no longer available.
Finally, if the Base Plan of a Bundle containing Sports
and OilSlick
is upgraded to Super
, Kill Bill knows to cancel the OilSlick
Plan because its features are already included, by default, in the new Base Plan.
<products>
<product name="Standard">
<category>BASE</category>
</product>
<product name="Sports">
<category>BASE</category>
<available>
<addonProduct>OilSlick</addonProduct>
<addonProduct>RemoteControl</addonProduct>
</available>
</product>
<product name="Super">
<category>BASE</category>
<included>
<addonProduct>OilSlick</addonProduct>
</included>
<available>
<addonProduct>RemoteControl</addonProduct>
</available>
</product>
<product name="OilSlick">
<category>ADD_ON</category>
</product>
<product name="RemoteControl">
<category>ADD_ON</category>
</product>
</products>
Price lists
Price Lists are collections of Plans, usually associated with a promotion or discount package. For example, we might offer special rates on our Spy Car rental package for CIA Agents, which offers 33% off for the first 3 months of hire.
To do this, we create plans similar to the ones we have already. They should have the same trial phase and the same evergreen phase, but we insert a new discount phase which, for 3 months, charges the appropriate discount.
In this example we consider only the first of the three additional plans.
<plan name="discount-standard-monthly">
<product>Standard</product>
<initialPhases>
<phase type="TRIAL">
<duration>
<unit>DAYS</unit>
<number>30</number>
</duration>
<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
<fixedPrice> <!-- empty price implies $0 -->
</fixedPrice>
</phase>
<phase type="DISCOUNT">
<duration>
<unit>MONTHS</unit>
<number>3</number>
</duration>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price>
<currency>GBP</currency>
<value>50.00</value>
</price>
<price>
<currency>USD</currency>
<value>66.00</value>
</price>
</recurringPrice>
</phase>
</initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
</duration>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price>
<currency>GBP</currency>
<value>75.00</value>
</price>
<price>
<currency>USD</currency>
<value>100.00</value>
</price>
</recurringPrice>
</finalPhase>
</plan>
Once our additional plans have been created, we can add the new pricelist, after the default price list:
<priceLists>
<defaultPriceList name="DEFAULT">
<plans>
<plan>standard-monthly</plan>
<plan>sports-monthly</plan>
<plan>super-monthly</plan>
</plans>
</defaultPriceList>
<childPriceList name="CIA">
<plans>
<plan>discount-standard-monthly</plan>
<plan>discount-sports-monthly</plan>
<plan>discount-super-monthly</plan>
</plans>
</childPriceList>
</priceLists>
The alignment and price list change rules can be used to specify the behaviour to use when changing pricelists. In the example above, we would expect customers to be able to upgrade and downgrade within the discount phase of the subscription and stay in the discounted price list. We refer to this as a "sticky" price list. Kill Bill can also support "non-sticky" price lists, in which plan changes cause the customer to drop out of the pricelist that they are in and move to a different one (usually the Default). In the section on rules we explain how to configure these properties.
Rules
There are several different Rules that can be configured in the Kill Bill Catalog. Each Rule answers a specific question. For example, one of the Rules answers the question "When should this plan change be applied?". Suppose Kill Bill receives a request for a subscription to have its plan upgraded, Kill Bill will check the rules, and based on the current plan, the phase it is in, the new plan etc. Kill Bill can determine whether the transition should happen immediately, or be deferred until later.
Rules consist of a series of Cases. Each Case is represented by a Predicate and a Result. Rules are evaluated against a Context. Each Case is examined in order, and the Predicate for that Case is compared to the Context. If the Context satisfies the Predicate, then Kill Bill applies the Result of that Case.
For example, consider the following rule for the timing of applying a plan change:
-
Predicate: phaseType=TRIAL ; Result: IMMEDIATE
-
Predicate: phaseType=Evergreen AND fromProduct=Sports AND toProduct=Standard ; Result: END_OF_TERM
-
Predicate: ; Result: END_OF_TERM
In this example there are three cases. The cases are evaluated from first to last and the first case for which the predicate matches the context is the one that is successful.
Consider the following Context:
phaseType |
EVERGREEN |
fromProduct |
Sports |
fromProductCategory |
BASE |
fromBillingPeriod |
MONTHLY |
fromPriceList |
DEFAULT |
toProduct |
Standard |
toProductCategory |
BASE |
toBillingPeriod |
MONTHLY |
toPriceList |
DEFAULT |
To evaluate the Rule against this Context, we start by considering Case 1. The predicate in Case 1 requires that PhaseType=TRIAL, but the first line of our context has phaseType set to EVERGREEN, so Case 1 fails. However, when we consider Case 2, all the predicate clauses are satisfied by the above context: phaseType=Evergreen, fromProduct=Sports and toProduct=Standard. So, Case 2 succeeds and the Rule evaluates to "END_OF_TERM".
Notice that the predicates only need to specify the values of some of the fields in the context. Fields that are omitted in a predicate can take any value. For this reason Case 3 is a catch-all Case. It always succeeds because the predicate has no clauses so it will succeed with any Context.
The XML for the above rules is given below:
<rules>
...
<changePolicy>
<changePolicyCase>
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
<phaseType>EVERGREEN</phaseType>
<fromProduct>Sports</fromProduct>
<toProduct>Standard</toProduct>
<policy>END_OF_TERM</policy>
</changePolicyCase>
<changePolicyCase>
<policy>END_OF_TERM</policy>
</changePolicyCase>
</changePolicy>
...
</rules>
There are three types of Context:
-
Creation Context - provides the context for a new subscription
-
Subscription Context - provides the context of an existing subscription, including details of the plan, phase, pricelist, product etc.
-
Change Context - provides the context not only about the phase of the current subscription but also details of the new target plan. This is used in the event of a plan change.
Creation Context | Subscription Context | Change Context |
---|---|---|
product |
product |
phaseType |
productCategory |
productCategory |
fromProduct |
billingPeriod |
billingPeriod |
fromProductCategory |
priceList |
priceList |
fromBillingPeriod |
phaseType |
fromPriceList |
|
toProduct |
||
toProductCategory |
||
toBillingPeriod |
||
toPriceList |
In the remainder of this section we illustrate each type of rule supported by the system.
Billing Alignment Rules
Billing alignment is concerned with specifying the day on which a particular subscription is to be billed. If an account has multiple subscriptions it is often desirable that they be billed on the same day.
If the billing period for a subscription is MONTHLY or a multiple of MONTHLY (such as QUARTERLY, ANNUAL, etc.) then we define the Bill Cycle Day (BCD). This is the date on which the billing occurs for that subscription each month. If multiple subscriptions have the same BCD, they may be billed on the same invoice. However, if the BCD for a new subscription differs from its start date, then the initial bill will have to be prorated. This will also occur anytime the BCD for a subscription is changed.
If a BCD falls on a date past the end of a given month, such as April 31, it will be set to the last day of that month.
The Billing Alignment Rules specify the policy for billing alignment for the current subscription. There are three kinds of alignment available:
-
ACCOUNT - this alignment means that the billing cycle of the subscription will be lined up with the BCD of the account. If a day value is not specified, the system will generate one using the first recurring bill date of all subscriptions with an
ACCOUNT
billing alignment. In some cases this is undesirable, because it means that the bill amount will need to be prorated on the first billing to line up the cycles. -
SUBSCRIPTION - this alignment will cause the subscription’s bill cycle to line up with the first bill day of the subscription plan. For example, if the subscription starts on January 3rd and has a 15 day free trial, the first billed day will be January 18th, and the BCD for the subscription will be set to 18.
-
BUNDLE - this alignment sets the BCD to the same day the base plan is using. This may be useful for add-ons.
For example, suppose we have a MONTHLY subscription, billed on the 15th of the month, and we add an ANNUAL subscription. If we start the ANNUAL on the 8th, we have 2 choices:
-
We can use an ACCOUNT alignment, so everything gets invoiced on the 15th. This would require an initial proration for the ANNUAL subscription from the 8th to the 15th, to align it with the MONTHLY subscription.
-
We can use a SUBSCRIPTION alignment and keep the ANNUAL on its own invoice, once a year on the 8th. This avoids any leading proration, but requires separate invoices.
The next example will align addons with the base plan, monthlies to the Account bill cycle day and annuals to their first billed day. Anything else is aligned with the Account.
<billingAlignment>
<billingAlignmentCase>
<productCategory>ADD_ON</productCategory>
<alignment>BUNDLE</alignment>
</billingAlignmentCase>
<billingAlignmentCase>
<billingPeriod>MONTHLY</billingPeriod>
<alignment>ACCOUNT</alignment>
</billingAlignmentCase>
<billingAlignmentCase>
<billingPeriod>ANNUAL</billingPeriod>
<alignment>SUBSCRIPTION</alignment>
</billingAlignmentCase>
<billingAlignmentCase>
<alignment>ACCOUNT</alignment>
</billingAlignmentCase>
</billingAlignment>
Subscription Alignment Rules
Plan Creation Add-On Phase Alignment
This rule also uses the Creation Context and determines how the phases of an Add-On plan align with an existing subscription.
There are two choices (illustrated below):
-
START_OF_BUNDLE - causes the phases of the add-on to start on the date when the base plan was first created. This is useful, for instance, if you want to allow add-on trials during the trial phase of the base plan only. The add-on plans must have a trial of the same length as the base plan, so the trials will expire at the same time whenever the add-on is created.
-
START_OF_SUBSCRIPTION - this causes the phases of the add-on to start when the add-on subscription is created. This is useful, for instance, if you want to allow add-ons to have trials that occur independently of the base plan.
Example:
-
Predicate: product=OilSlick ; Result: START_OF_BUNDLE
-
Predicate: product=RemoteControl ; Result: START_OF_SUBSCRIPTION
-
Predicate: ; Result: START_OF_BUNDLE
In this example the product OilSlick
is aligned to the START_OF_BUNDLE and the product RemoteControl
is aligned to START_OF_SUBSCRIPTION. The default for anything else is START_OF_BUNDLE.
<createAlignment>
<createAlignmentCase>
<product>OilSlick</product>
<alignment>START_OF_BUNDLE</alignment>
</createAlignmentCase>
<createAlignmentCase>
<product>RemoteControl</product>
<alignment>START_OF_SUBSCRIPTION</alignment>
</createAlignmentCase>
<createAlignmentCase>
<alignment>START_OF_BUNDLE</alignment>
</createAlignmentCase>
</createAlignment>
For more information on Plan Creation Phase Alignment
, and in particular to understand how that works with apis (Subscription Create or Subscription Change Plan) that specify a target PhaseType
, you can also refer to this documentation.
Plan Cancellation Timing
This rule uses the Phase Context and is used to specify when a cancellation should occur.
There are two options (illustrated below):
-
END_OF_TERM - means that the cancellation will be applied at the end of the billed period. This is typical in a situation where we want to avoid generating credits.
-
IMMEDIATE - means that the cancellation will be applied immediately and the customer credited with the balance of the subscription that they have paid for but not yet used.
Example:
-
Predicate: productCategory=BASE ; Result: END_OF_TERM
-
Predicate: productCategory=ADD_ON ; Result: IMMEDIATE
-
Predicate: ; Result: END_OF_TERM
In this example base plans are cancelled at the end of their term, while add-on plans are cancelled immediately.
<cancelPolicy>
<cancelPolicyCase>
<productCategory>BASE</productCategory>
<policy>END_OF_TERM</policy>
</cancelPolicyCase>
<cancelPolicyCase>
<productCategory>ADD_ON</productCategory>
<policy>IMMEDIATE</policy>
</cancelPolicyCase>
<cancelPolicyCase>
<policy>END_OF_TERM</policy>
</cancelPolicyCase>
</cancelPolicy>
Plan Change Timing
This rule uses the Change Context and, like the cancellation rule above, specifies when a plan change should occur.
There are three options (two of which are illustrated above):
-
END_OF_TERM - specifies that the change should happen at the end of the current billed period.
-
IMMEDIATE - specifies that the change should happen when requested.
-
ILLEGAL - plan change is not allowed (not illustrated).
Example:
-
Predicate: phaseType=TRIAL ; Result: IMMEDIATE
-
Predicate: fromProduct=Standard AND toProduct=Sports ; Result: IMMEDIATE
-
Predicate: toProduct=Super ; Result: IMMEDIATE
-
Predicate: ; Result: END_OF_TERM
In this example we specify that trials and upgrades occur immediately, anything else is to occur at end of term.
<changePolicy>
<changePolicyCase>
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
<fromProduct>Standard</fromProduct>
<toProduct>Sports</toProduct>
<policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
<toProduct>Super</toProduct>
<policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
<policy>END_OF_TERM</policy>
</changePolicyCase>
</changePolicy>
Plan Change Phase Alignment
In the section "Plan Creation Add-on Phase Alignment" above, we specified how to align the phases of an add-on with a base plan. This rule, which uses the Change Context, specifies how the phases of a new plan should align with the phases of the existing plan when a plan is changed.
There are four options:
-
START_OF_SUBSCRIPTION - The plan phases start with the start of the subscription. This is the most common alignment and applies in most situations.
-
START_OF_BUNDLE - The plan phases align with the start of the base subscription. This is only meaningful for addons.
-
CHANGE_OF_PLAN - The plan phases start at the time of the change
-
CHANGE_OF_PRICELIST - The plan phases start at the time of the price list’s last change
Example:
-
Predicate: toProductCategory=ADD_ON ; Result: START_OF_BUNDLE
-
Predicate: toPriceList=SpecialDiscount ; Result: CHANGE_OF_PRICELIST
-
Predicate: ; Result: START_OF_SUBSCRIPTION
<changeAlignment>
<changeAlignmentCase>
<toProductCategory>ADD_ON</toProductCategory>
<alignment>START_OF_BUNDLE</alignment>
</changeAlignmentCase>
<changeAlignmentCase>
<fromPriceList>SpecialDiscount</fromPriceList>
<toPriceList>SpecialDiscount</toPriceList>
<alignment>CHANGE_OF_PRICELIST</alignment>
</changeAlignmentCase>
<changeAlignmentCase>
<alignment>START_OF_SUBSCRIPTION</alignment>
</changeAlignmentCase>
</changeAlignment>
In this example, add-on changes are aligned to the start of the bundle, changes to the SpecialDiscount
price list are aligned to that change, and everything else aligns to the start of the subscription.
For more information on Plan Change Phase Alignment
, and in particular to understand how that works with apis (Subscription create or Subscription Change Plan) that specify a target PhaseType
, you can also refer to this documentation.
Plan Change Price List Choice
This rule uses the Change Context and specifies which pricelist should be chosen for specific changes. The rule allows us to configure whether a price list is "sticky" or not.
For example, suppose we have an affiliate pricelist with special prices for members of the CIA for Spy Car rental. Let’s say that this price list offers a 30% discount for the first 3 months of rental.
Now, Special Agent Mills from the CIA subscribes to a Sports
product on that price list. However, 1 month after renting the car his daughter is kidnapped and he needs additional capabilities and decides to upgrade to a Super
.
Since he bought the original subscription on a special offer that still has two months to run we would expect the upgrade to put him into the corresponding 30% off Super
plan and give him a further 2 months at that price. This is a "sticky" price list.
Alternatively, consider long term customer 003 who has been renting the Super
for the last 4 years but decides that she wants to save money and calls to downgrade her plan. Our representative offers her a special Rescue Pricing plan that gives her 40% off for the next year and she decides to take it.
However, a month later she changes her mind and decides to downgrade anyway. In this situation we want her to downgrade to the default price plan. This is a "non-sticky" price list.
Example:
-
Predicate: fromPriceList=CIA ; Result: CIA
-
Predicate: fromPriceList=SpecialDiscount ; Result: DEFAULT
-
Predicate: ; Result: DEFAULT
<priceList>
<priceListCase>
<fromPriceList>SpecialDiscount</fromPriceList>
<toPriceList>DEFAULT</toPriceList>
</priceListCase>
<priceListCase>
<fromPriceList>CIA</fromPriceList>
<toPriceList>CIA</toPriceList>
</priceListCase>
<priceListCase>
<toPriceList>DEFAULT</toPriceList>
</priceListCase>
</priceList>
Catalog Versions
This far in the discussion we have been considering single stand-alone catalogs, but Kill Bill allows you to modify the catalog over time. You can do this by creating a set of catalogs, one XML file for each version; the system will rank such files based on their effectiveDate
to create the various versions. There is no version number proper; the effectiveDate
associated with each catalog XML constitutes the version and the next catalog supersedes the previous one. In this way we can change prices, add new Plans, Products, Price Lists etc, retire Plans, Products, Price Lists, etc.
Note that it is possible to remove entries in subsequent catalog versions. For example, removing a Plan
in a new catalog version would prevent future customers from subscribing to that Plan
. However existing subscriptions may still refer to it.
Deferred Price Change
Kill Bill supports the ability to make a price change to a plan that applies based on the catalog effective date for new purchases, but which is deferred for existing subscriptions. It is often the case that existing customers will need a notice period before prices are changed but you need to deliver the new prices to new purchases as soon as the change is announced.
This feature uses the field effectiveDateForExistingSubscriptions
that is included on Plans.
The semantics is simply that the changes to that plan will only take effect for existing subscriptions, after that date, but new subscription would use the new price immediately.
The drawing below summarizes how the system would apply the change for an existing subscription:
Usage Billing
Usage Modes
Kill Bill supports billing customers based on their usage data, and the pricing schemes for this billing are defined in the Kill Bill catalog.
The Plan
section of the catalog can contain one or several usage
section(s) to define how customers will be billed.
These sections can be defined in addition to other, non usage based, billing schemes, such as fixed or recurring price.
Each usage section will need to specify a billingMode
.
The only billing mode supported today is the IN_ARREAR
mode, which allows customers to be billed based on usage data from previous periods.
We plan to add the IN_ADVANCE
mode in the future to support prepaid scenarios such as toll bridge pass, where the customer purchases a
certain number of units in advance and such units are decremented as the customer uses the service.
Each usage section will also need to specify a usageType
and along with it, specify the unit
(types) for which the customer is being billed, such as cell phone/minutes.
The usage type can be one of the following:
-
CONSUMABLE
: This is used for defining prices that are based on the number of units (for a certain type) being consumed — e.g., water consumed in the last period. -
CAPACITY
: This is used for defining prices that are based on rates or upper bound values. In this scheme, we bill based on the maximum value that was seen over the period — e.g MBytes/sec
The following blog post provides additional context about these use cases.
For each usage section, we support defining pricing tiers, allowing customers to be billed differently based on their usage.
These tiers work differently depending on the usage type, CONSUMABLE
or CAPACITY
.
Each usage section also needs to define the billingPeriod
— e.g MONTHLY
— to define how often and for which period consumers are being billed.
Consumable In Arrear Mode
In this mode, each tier
definition contains a tieredBlock
that defines the limits and price associated with a particular unit
type. We support two TierBlockPolicy
policies:
-
ALL_TIER
: This policy charges users across each tier based on their usage. Higher prices are charged to the less preferred tier. This may be a lower tier, e.g for cloud usage where we want to reward users who consume more, or a higher tier, e.g for an electric bill where we want to encourage users to consume less. -
TOP_TIER
: With this policy we still go through each tier, but everything is charged at the top tier pricing. Here it makes sense to offer lower pricing for the top tier, since this is a rewarding model.
Consumable In Arrear Mode: ALL_TIER
To demonstate the ALL_TIER
policy, let’s start with an example of a tieredBlock
definition. The following tier block section defines the pricing for the cell-phone-minutes
unit, and can be understood the following way:
<tieredBlock>
<unit>cell-phone-minutes</unit>
<size>10</size>
<prices>
<price>
<currency>EUR</currency>
<value>1.00</value>
</price>
</prices>
<max>100</max>
</tieredBlock>
-
This defines a block of size
10
, where each block is priced at 1.00 EUR -
The first
100
blocks of this size will be priced at 1.00 EUR -
If a consumer uses more than
100
blocks of this size, he will be charged at the price of the next tier.
As mentioned previously, each usage section can contain multiple tiers and also charge for multiple unit types.
The following section shows the defintion for 2 units, cell-phone-minutes and Mbytes, and defines two tiers.
The max
value for the last tier is defined with -1 which represents an unbounded value:
<tiers>
<tier>
<blocks>
<tieredBlock>
<unit>cell-phone-minutes</unit>
<size>10</size>
<prices>
<price>
<currency>EUR</currency>
<value>1.00</value>
</price>
</prices>
<max>100</max>
</tieredBlock>
<tieredBlock>
<unit>Mbytes</unit>
<size>1</size>
<prices>
<price>
<currency>EUR</currency>
<value>0.5</value>
</price>
</prices>
<max>1024</max>
</tieredBlock>
</blocks>
</tier>
<tier>
<blocks>
<tieredBlock>
<unit>cell-phone-minutes</unit>
<size>10</size>
<prices>
<price>
<currency>EUR</currency>
<value>0.50</value>
</price>
</prices>
<max>-1</max>
</tieredBlock>
<tieredBlock>
<unit>Mbytes</unit>
<size>1</size>
<prices>
<price>
<currency>EUR</currency>
<value>0.1</value>
</price>
</prices>
<max>-1</max>
</tieredBlock>
</blocks>
</tier>
</tiers>
In the CONSUMABLE
mode, when defining a usage section with multiple unit (types), it is important to realize that the consumer is charged independently
for each unit. For example, with the definition provided above, and given the following usage data for the period:
-
1500 cell-phone-minutes
-
2048 Mbytes
The total amount would be 739.4. This is calculated as follows:
cell-phone-minutes:
-
Tier 1: 100 blocks of size 10 at 1 EUR ⇒ 100 EUR
-
Tier 2: 50 blocks of size 10 at 0.5 EUR ⇒ 25 EUR
Mbytes
-
Tier 1: 1024 blocks of size 1 at 0.5 EUR ⇒ 512
-
Tier 2: 1024 blocks of size 1 at 0.1 EUR ⇒ 102.4
Total: 100 + 25 + 512 + 102.4 = 739.4
For more information on this model, see our tutorial.
Consumable In Arrear Mode: TOP_TIER
Using the same example from the previous section with the TOP_TIER
policy would lead to a different result, since all charges would be calculated at the higher tier:
-
cell-phone-minutes: 150 blocks of size 10 at 0.50 EUR = 150 * 0.5 = 75
-
Mbytes: 2048 blocks of size 1 at 0.10 EUR = 2048 * 0.1 = 204.8
So the total amount would be 279.8.
Capacity In Arrear Mode
In the CAPACITY
mode, each tier
definition contains a list of limit
, specifying the maximum value for this tier for each unit
(type). In contrast to the CONSUMABLE
mode, the billing happens across the units. Let’s assume the following definition for one tier, with 2 different types of units, bandwith-meg-sec
and members
:
<tier>
<limits>
<limit>
<unit>bandwith-meg-sec</unit>
<max>100</max>
</limit>
<limit>
<unit>members</unit>
<max>500</max>
</limit>
</limits>
<recurringPrice>
<price>
<currency>EUR</currency>
<value>5.00</value>
</price>
</recurringPrice>
</tier>
Given the following usage data for the period:
-
bandwith-meg-sec
: A peak of 50 in the period -
members
: A peak of 350 active members in the period
The user would be charged 5.00 EUR.
However if the members
peak data was 501, this would move to the next tier — not shown for simplicity.
So, in this model, the peak data for each unit is used to define which tier to use, and based on the tier we simply apply the pricing defined.
Subscription and Entitlement
Overview
The Kill Bill entitlement system offers an API for users to manage their subscriptions. The API allows a user to subscribe to a new product, change to a different product, pause, resume or cancel a subscription. Upon each of those API calls, there are two distinct sets of operations that occur in the system:
-
When an entitlement change occurs, for instance upon creation, the user gains access to what she subscribed for. The primary goal of that API is to give great flexibility through the use of dates or entitlement policies as to when things should start or stop.
-
As a consequence of the entitlement operation, the system will also compute the changes that should occur on the billing side. It is important to understand that the entitlement operation has an impact on billing, so the two are connected, but they are not necessarily aligned.
The philosophy behind that API is that the user (of the API) should be able to configure the entitlement so that it matches their needs exactly, and let the system compute the billing aspect based on the policies that were configured in the catalog.
Example:
-
First an administrator sets up Kill Bill to always perform the cancellation END_OF_TERM, which will result in never generating a credit for a particular product 'P'.
-
A customer comes in, subscribes to that product 'P', and gets invoiced.
-
At a later date the customer decides that he no longer wants to use the product 'P', and decides to cancel that subscription immediately. From an entitlement point of view, the end date is now. So as soon as the call returns, the customer loses access to the product.
-
From a billing point of view, however, because the administrator decided to configure the system that way, the system will compute the end date to match the end date of the last period invoiced, also referred to as "charged through date" (CTD). Thus there is no generated credit for that cancellation.
As a general rule, then, the administrator deals with the billing policies, and the user of the API controls the details of its entitlement(s). The entitlement system exposes abstractions that reflect that model:
-
Entitlement: An entitlement is an abstraction which provides the answer to the following question: Is the user allowed (entitled) to use this service or product at a given time? It provides information about the dates when that service started, ended, or was paused and resumed, along with the specifics about the type of service or product.
-
Subscription: A Subscription is an abstraction that encapsulates the information contained in the entitlement but also adds additional billing information, such as the dates at which the billing started and ended. When the system is configured to bill in advance, it also provides the date up to which the customer was invoiced (ChargeThroughDate).
-
SubscriptionBundle: Subscriptions are always part of a SubscriptionBundle. This allows Subscriptions to be grouped together so that specific operations — cancellation, change of plan-- on one Subscription may have an impact on the other Subscriptions in the same SubscriptionBundle. There can be at most one Subscription attached to a BASE Category in a SubscriptionBundle but there can be multiple ADD_ON Subscriptions in that same SubscriptionBundle. Typically, a BASE Category is used to make sure that any operation on the BASE Subscription will be reflected on the ADD_ON Susbcriptions in the same SubscriptionBundle.
Previously we laid out the general case where the user of the API controls the entitlement and Kill Bill manages the billing aspect based on configuration policies. Some specific entitlement APIs also allow you to override the billing policies on a per call basis.
Alignments
The table below shows the possible combinations that the API supports. The columns represent the various entitlement (ENT) policies: Immediate, End of Term, or specific date. The rows represent the possible billing policies, which have the same three choices.
The diagrams below illustrate each entry in the table, for the case when a cancellation occurs on a subscription that was billed in advance:
-
The green line shows the entitlement, and the red cross on that line shows the cancellation as seen by the customer; that is, once we hit the red cross the customer loses access to its entitlement.
-
The red portion below shows the current invoice; by default the customer was invoiced from the start of the period to the end of the period, also referred to as the charged through date (CTD).
We can see that in all cases, cancelling a subscription has both an impact on the entitlement and the billing side, but we also see that those two are not necessarily aligned:
Invoicing
Overview
Most billing system are batch oriented: Invoice calculation occurs at certain specific times (often configurable), and the system goes through all accounts and generate the missing invoices. Kill Bill, on the other hand, generates new invoices as soon as there is a change in the system that requires such a new invoice. This may occur, for example:
-
when there is a change to a subscription (creation, change of plan, cancellation, etc.)
-
when the system detects a recurring charge is due (e.g. monthly recurring subscriptions)
-
when an operator creates an external charge, adjusts a past invoice or triggers a future invoice
After an invoice has been generated, its balance is positive or zero. If it is positive, the customer owes money and needs to pay the balance. Each time an invoice would become negative, the system automatically inserts a special item, called credit balance adjustment (CBA), to bring the balance back to zero. That credit is automatically added to the account and used on future invoices. If the invoice is paid, a payment is added against that invoice. If the invoice is adjusted later on, a CBA item will be automatically generated and appear on the invoice. Kill Bill invoices are for the most part static, with the exceptions of manual changes (manual credit, charge added on a specific invoice after generation).
An invoice is composed of invoice items. The various types of invoice items are:
-
RECURRING: Recurring charge. Used for items with a billing period. This item is always positive or zero
-
FIXED: Fixed (one-time) charge. Used for items without a billing period (non recurring phase, e.g. trials). This item is always positive or zero
-
EXTERNAL_CHARGE: Fixed (one-time) external charge, for items not in the catalog. This item is always positive
-
USAGE: Usage charge. This item is always positive or zero.
-
TAX: Tax item. This item is not added by the core system, but is added by tax plugins — when such plugins exist.
-
ITEM_ADJ: Invoice item adjustment, generated by an operator (often associated with a refund). This item is always negative
-
CREDIT_ADJ: Invoice level adjustment (credits), either at the account level (on its own invoice) or against an existing invoice. This item is always negative
-
REPAIR_ADJ: Internal adjustment, generated automatically by the system for an invoice on which the subscription was modified (immediate cancellation or change). The items is always negative
-
CBA_ADJ: Internal adjustment, generated automatically by the system for an invoice which became negative (account level credits). Positive when generating credits, negative when consuming account level credits. The sum of CBA items for an account should always be positive or zero
Recurring invoice items start and end on the same day of the month. For example, a monthly subscription starting on the 21st will have items for the service period 2012-08-21 to 2012-09-21, 2012-09-21 to 2012-10-21, etc. Fixed items only have a start date and never get prorated.
Invoice and Account Balance
The invoice balance is computed by adding all the charges, subtracting credits and adjustments, and then subtracting the amount paid.
-
The charge amount is computed from the following items: FIXED, RECURRING, EXTERNAL_CHARGE, REPAIR_ADJ, ITEM_ADJ, USAGE, TAX.
-
The resulting paid amount is equal to the original paid amount after subtracting any refund amount.
The invoice balance is zero in the following cases:
-
When the invoice was tagged with the WRITTEN_OFF tag.
-
When the invoice is in DRAFT mode.
-
When this is a migration invoice (imported in the system).
-
When this is a child invoice for which the parent summary invoice has been fully paid (HA feature).
The account balance is the sum of all the invoice balances after subtracting any account credit. For example, if all invoices were fully paid, and if there was a $10 account credit, the account balance would be negative and equal to -$10.
Invoice Items
Fixed Item
An invoice for a subscription on a fixed phase of $0 (trial phase for example) would look like:
Invoice # | Type | Description | Amount | Start date | End date |
---|---|---|---|---|---|
1028 |
FIXED |
Silver trial |
$0 |
2013-03-10 |
Recurring Item
An invoice for a subscription on a recurring phase of $20 would look like:
Invoice # | Type | Description | Amount | Start date | End date |
---|---|---|---|---|---|
1029 |
RECURRING |
Silver monthly |
$20 |
2013-04-11 |
2013-05-11 |
Plan Changes
In a case where invoicing occurs in advance, a user gets charged for the upcoming period. For instance a user that subscribed to a monthly plan on 2013-04-11, would get a first invoice, charging for that month. Assuming he paid his invoice, his balance is now 0. Let’s assume he decides to upgrade on 2013-04-26:
Previous invoice:
Invoice # | Type | Description | Amount | Start date | End date |
---|---|---|---|---|---|
1029 |
RECURRING |
Silver monthly |
$20 |
2013-04-11 |
2013-05-11 |
On the new invoice, the system will generate a REPAIR_ADJ item for the part of the subscription on the old plan that was not used, and a new RECURRING item for the new plan on the remaining period.
Invoice # | Type | Description | Amount | Start date | End date |
---|---|---|---|---|---|
1030 |
RECURRING |
Gold monthly |
$15 |
2013-04-26 |
2013-05-11 |
1029 |
REPAIR_ADJ |
Silver monthly |
$-10 |
2013-04-26 |
2013-05-11 |
Note that if the absolute value of the amount of the REPAIR_ADJ had been greater than the amount of the new RECURRING item, the system would have generated a CBA_ADJ item whose purpose would have been to bring the balance to 0, and provide the customer some credit that would have been used on subsequent invoices.
Invoice Item Adjustment
An invoice item adjustment would look like (assuming the invoice wasn’t paid, otherwise a CBA_ADJ item would be added):
Invoice # | Type | Description | Amount | Start date | End date |
---|---|---|---|---|---|
1029 |
RECURRING |
Silver monthly |
$20 |
2013-04-11 |
2013-05-11 |
1029 |
ITEM_ADJ |
$-20 |
2013-04-20 |
2013-04-20 |
Credit
Note that CREDIT_ADJ items are also used to represent credits created by the user (via APIs). In this case, a dummy invoice is created with a negative amount for the CREDIT_ADJ item. This makes the system generate a CBA_ADJ automatically, which in turn can be used as account credits. For example, here is how a $20 credit would be represented:
Invoice # | Type | Description | Amount | Start date | End date |
---|---|---|---|---|---|
1029 |
CREDIT_ADJ |
$-20 |
2013-04-20 |
2013-04-20 |
|
1029 |
CBA_ADJ |
$20 |
2013-04-20 |
2013-04-20 |
Invoice Dry Run
Dry Run Modes
In some situations, it is necessary to preview what a given customer will be invoiced for at a given date or after making a subscription change. Kill Bill provides dry-run invoice apis to accomplish such a goal, and there are a few flavours for different use cases:
-
Next upcoming invoice: When is the next upcoming invoice for a given customer, and what will this invoice contain (items, amount, date, …)?
-
Next upcoming invoice associated with a given subscription or bundle: When is the next upcoming invoice for a given subscription/bundle, and what will this invoice contain (items, amount, date, …)?
-
Given a targetDate, what invoice will the system generate ?
-
Subscription modification: Given a change in a subscription (new subscription, change of plan, cancellation, …), what invoice will the system generate ?
Let’s assume a scenario where we created 2 annual subscriptions, the first one 261fe7b1-ff09-49c8-bbef-61d6e3ab876b
aligned
on July 25 and the second one 06b826ad-73e6-4bdd-92fe-c9770a1ba30a
aligned on July 27.
If we look at the existing invoice items we see the following:
*************************** 1. row ***************************
id: 079e572e-a26c-42e4-8676-7213ad542af3
account_id: 704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3
invoice_id: 5725c77f-44af-409c-a32a-e36ed3c57283
subscription_id: 261fe7b1-ff09-49c8-bbef-61d6e3ab876b
type: RECURRING
amount: 10000.000000000
start_date: 2017-07-25
end_date: 2018-07-25
*************************** 2. row ***************************
id: 1674c034-fcbe-46bb-9c04-f8825671f93f
account_id: 704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3
invoice_id: 65c5b4b8-67e6-4066-8699-70b0f49ee6df
subscription_id: 06b826ad-73e6-4bdd-92fe-c9770a1ba30a
type: RECURRING
amount: 10000.000000000
start_date: 2017-07-27
end_date: 2018-07-27
From this scenario, let’s now look at various use cases for dry-run options:
Next Upcoming Invoice
Let’s start with a dry-run invoice with UPCOMING_INVOICE
, to see the next invoice that the system will generate for this account:
curl \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "X-Killbill-CreatedBy: demo" \
-H "Content-Type: application/json" \
--data-binary '{"dryRunType":"UPCOMING_INVOICE"}' \
'http://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3'
This will result in the following dry-run invoice. As expected, we only see the item for the first subscription aligned on the 25th:
{
"amount": 10000,
"currency": "USD",
"status": "COMMITTED",
"creditAdj": 0,
"refundAdj": 0,
"invoiceId": "3bbd33da-39c7-4748-a5a8-94d53e40cadc",
"invoiceDate": "2017-12-14",
"targetDate": "2018-07-25",
"invoiceNumber": null,
"balance": 10000,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"bundleKeys": null,
"credits": null,
"items": [
{
"invoiceItemId": "937ac911-b51c-48a8-a004-4789bd3e0726",
"invoiceId": "3bbd33da-39c7-4748-a5a8-94d53e40cadc",
"linkedInvoiceItemId": null,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"childAccountId": null,
"bundleId": "54c2d76e-e84d-412d-8eac-afb6d0ea1a35",
"subscriptionId": "261fe7b1-ff09-49c8-bbef-61d6e3ab876b",
"planName": "basic-annual",
"phaseName": "basic-annual-evergreen",
"usageName": null,
"itemType": "RECURRING",
"description": "basic-annual-evergreen",
"startDate": "2018-07-25",
"endDate": "2019-07-25",
"amount": 10000,
"currency": "USD",
"childItems": null,
"auditLogs": null
}
],
"isParentInvoice": false,
"auditLogs": null
}
Next Upcoming Invoice for a Given Subscription
Let’s now do a dry-run invoice with UPCOMING_INVOICE
but with a filter on the subscription 06b826ad-73e6-4bdd-92fe-c9770a1ba30a
:
curl \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "X-Killbill-CreatedBy: demo" \
-H "Content-Type: application/json" \
--data-binary '{"dryRunType":"UPCOMING_INVOICE", "subscriptionId":"06b826ad-73e6-4bdd-92fe-c9770a1ba30a"}' \
'http://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3'
This will result in the following dry-run invoice. This time, as expected, we only see the item for the second subscription 06b826ad-73e6-4bdd-92fe-c9770a1ba30a
:
{
"amount": 10000,
"currency": "USD",
"status": "COMMITTED",
"creditAdj": 0,
"refundAdj": 0,
"invoiceId": "25fbf3f9-2b5b-4389-a940-84864fe5cd88",
"invoiceDate": "2017-12-14",
"targetDate": "2018-07-27",
"invoiceNumber": null,
"balance": 10000,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"bundleKeys": null,
"credits": null,
"items": [
{
"invoiceItemId": "a4f525c4-014b-474b-85a9-6ccf4742fe5e",
"invoiceId": "25fbf3f9-2b5b-4389-a940-84864fe5cd88",
"linkedInvoiceItemId": null,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"childAccountId": null,
"bundleId": "c056fac0-1564-46cd-9e2a-d97e49e30177",
"subscriptionId": "06b826ad-73e6-4bdd-92fe-c9770a1ba30a",
"planName": "basic-annual",
"phaseName": "basic-annual-evergreen",
"usageName": null,
"itemType": "RECURRING",
"description": "basic-annual-evergreen",
"startDate": "2018-07-27",
"endDate": "2019-07-27",
"amount": 10000,
"currency": "USD",
"childItems": null,
"auditLogs": null
}
],
"isParentInvoice": false,
"auditLogs": null
}
Next Invoice for a Given Target Date
Next, let’s run a dry-run invoice with TARGET_DATE
set to 2018-07-27
:
curl \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "X-Killbill-CreatedBy: demo" \
-H "Content-Type: application/json" \
--data-binary '{"dryRunType":"TARGET_DATE"}' \
'http://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3&targetDate=2018-07-27'
This will produce the following dry-run invoice, and we will see the same result as in the previous example. However, while the previous use case answered the question about the next upcoming invoice for subscription 06b826ad-73e6-4bdd-92fe-c9770a1ba30a
, in this scenario we answer a different question: Given a targetDate what will the system generate?
{
"amount": 10000,
"currency": "USD",
"status": "COMMITTED",
"creditAdj": 0,
"refundAdj": 0,
"invoiceId": "d89d776a-b13e-4c53-baad-519bdd9ba6d0",
"invoiceDate": "2017-12-14",
"targetDate": "2018-07-27",
"invoiceNumber": null,
"balance": 10000,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"bundleKeys": null,
"credits": null,
"items": [
{
"invoiceItemId": "9a872df2-1ab9-4250-8f34-8b2cf49ebbb9",
"invoiceId": "d89d776a-b13e-4c53-baad-519bdd9ba6d0",
"linkedInvoiceItemId": null,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"childAccountId": null,
"bundleId": "c056fac0-1564-46cd-9e2a-d97e49e30177",
"subscriptionId": "06b826ad-73e6-4bdd-92fe-c9770a1ba30a",
"planName": "basic-annual",
"phaseName": "basic-annual-evergreen",
"usageName": null,
"itemType": "RECURRING",
"description": "basic-annual-evergreen",
"startDate": "2018-07-27",
"endDate": "2019-07-27",
"amount": 10000,
"currency": "USD",
"childItems": null,
"auditLogs": null
}
],
"isParentInvoice": false,
"auditLogs": null
}
Subscription Modification
Finally, we’ll generate a dry-run invoice associated with a change in the subscription. We want to see what kind of invoice would be generated if we were to change the billing period from ANNUAL
to MONTHLY
. Note that this change was made on 2018-01-24:
curl -X POST \
-u admin:password \
-H 'Content-Type: application/json' \
-H 'X-Killbill-ApiKey: bob' \
-H 'X-Killbill-ApiSecret: lazar' \
-H 'X-Killbill-CreatedBy: demo' \
-d '{"bundleId":"c056fac0-1564-46cd-9e2a-d97e49e30177", "dryRunType":"SUBSCRIPTION_ACTION", "phaseType":"EVERGREEN", "productName":"Basic", "productCategory":"BASE", "billingPeriod":"MONTHLY", "priceListName":"DEFAULT", "subscriptionId":"06b826ad-73e6-4bdd-92fe-c9770a1ba30a", "billingPolicy":"IMMEDIATE", "dryRunAction":"CHANGE"}' \
"http://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3"
The result is an invoice with 3 items:
-
A
RECURRING
item to invoice the next MONTHLY period -
A
REPAIR_ADJ
item to generate a credit for the remaining part of the year -
A`CBA_ADJ` item to bring the balance to 0 and generate the resulting account credit.
This invoice is shown below:
{
"amount": -5008.84,
"currency": "USD",
"status": "COMMITTED",
"creditAdj": 5008.84,
"refundAdj": 0,
"invoiceId": "e85306e2-2753-4888-b7df-543c308c367c",
"invoiceDate": "2018-01-24",
"targetDate": "2018-01-24",
"invoiceNumber": null,
"balance": 0,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"bundleKeys": null,
"credits": null,
"items": [
{
"invoiceItemId": "f2156511-0273-4ef0-9c11-410a3f6f3872",
"invoiceId": "e85306e2-2753-4888-b7df-543c308c367c",
"linkedInvoiceItemId": null,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"childAccountId": null,
"bundleId": "c056fac0-1564-46cd-9e2a-d97e49e30177",
"subscriptionId": "06b826ad-73e6-4bdd-92fe-c9770a1ba30a",
"planName": "basic-monthly",
"phaseName": "basic-monthly-evergreen",
"usageName": null,
"itemType": "RECURRING",
"description": "basic-monthly-evergreen",
"startDate": "2018-01-24",
"endDate": "2018-01-25",
"amount": 32.26,
"currency": "USD",
"childItems": null,
"auditLogs": null
},
{
"invoiceItemId": "f78a8843-3155-4f89-ae2a-ca4219936a2c",
"invoiceId": "e85306e2-2753-4888-b7df-543c308c367c",
"linkedInvoiceItemId": "1674c034-fcbe-46bb-9c04-f8825671f93f",
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"childAccountId": null,
"bundleId": null,
"subscriptionId": null,
"planName": null,
"phaseName": null,
"usageName": null,
"itemType": "REPAIR_ADJ",
"description": "Adjustment (subscription change)",
"startDate": "2018-01-24",
"endDate": "2018-07-27",
"amount": -5041.1,
"currency": "USD",
"childItems": null,
"auditLogs": null
},
{
"invoiceItemId": "4b13e745-eaa7-4fcd-bfc8-56a3ff3d5190",
"invoiceId": "e85306e2-2753-4888-b7df-543c308c367c",
"linkedInvoiceItemId": null,
"accountId": "704b1a30-e5b9-4d01-b2b8-e9403a0ed0e3",
"childAccountId": null,
"bundleId": null,
"subscriptionId": null,
"planName": null,
"phaseName": null,
"usageName": null,
"itemType": "CBA_ADJ",
"description": "Adjustment (account credit)",
"startDate": "2018-01-24",
"endDate": "2018-01-24",
"amount": 5008.84,
"currency": "USD",
"childItems": null,
"auditLogs": null
}
],
"isParentInvoice": false,
"auditLogs": null
}
Usage Billing
Usage Invoice Items
As described in the section Usage Billing,
Kill Bill supports invoicing customers based on different usage types. The usage billing is always done on a per subscription
level and for a given billing period; in addition, if the active Plan
associated with the subscription contains multiple usage
sections, each usage section is billed independently: As a result, we may see one or several USAGE
invoice items per invoice,
each associated with a given subscription, usage section and billing period.
Regardless of the usage type the following basic fields will always be seen:
-
planName
: The name of thePlan
in the catalog -
phaseName
: The name of thePlanPhase
in the catalog -
subscriptionId
: The ID of the subscription -
usageName
: The name of the usage section in the catalog -
startDate
: The start date for the period being invoiced -
endDate
: The end date for the period being invoiced
In addition, depending on the usage type for the usage section (e.g CONSUMABLE
), and depending on the configuration of the system,
we may see additional information.
Capacity In Arrear Mode
This mode bills based on actual usage, using a fixed price for the highest tier reached. For each capacity in arrear usage section, we will see some json in the field itemDetails
, to provide additional information:
{
"tierDetails": [
{
"tier": 2,
"tierUnit": "bandwith-meg-sec",
"tierPrice": 10,
"quantity": 200
},
{
"tier": 3,
"tierUnit": "members",
"tierPrice": 100,
"quantity": 60
}
],
"amount": 100
}
In this example we see that we were invoiced for 2 different units, and this shows the tier details for each unit, and the amount that will be charged.
Because unit members
reached tier 3, the amount will be based on the pricing for this tier.
Consumable In Arrear Mode
This mode bills for each unit based on actual usage, using a price determined by the tier(s) reached and by the policy. With the ALL_TIER
policy, usage within each tier is charged according to the price for that tier. With the TOP_TIER
policy, all usage is charged according to the price for the highest tier reached.
We can configure the invoicing system to output one amount per tier (Detail Mode), or a single amount for all tiers (Aggregate Mode). The example below illustrates each mode for the ALL_TIER
policy.
Aggregate Mode
In the aggregate mode, we will see one USAGE
item with the aggregate amount across units and tiers. The itemDetails
json will summarize the usage on a per tier basis and per unit basis:
{
"tierDetails": [
{
"tier": 1,
"tierUnit": "cell-phone-minutes",
"tierPrice": 2,
"tierBlockSize": 1,
"quantity": 20,
"amount": 40
},
{
"tier": 2,
"tierUnit": "cell-phone-minutes",
"tierPrice": 20,
"tierBlockSize": 1,
"quantity": 100,
"amount": 2000
},
{
"tier": 1,
"tierUnit": "Mbytes",
"tierPrice": 10,
"tierBlockSize": 1,
"quantity": 10,
"amount": 100
}
],
"amount": 2140
}
In this example, we have billed for two unit types: cell-phone-minutes
and Mbytes
. For cell-phone-minutes
, the quantity recorded for the period reached the maximum for tier 1 and extended into tier 2. Since we are using the ALL_TIER
policy, the amount for each tier is computed separately, giving 40 for tier 1 and 2000 for tier 2. For the Mbytes
units, all usage remained in tier 1, so a single amount, 100, is computed. The amount reported is the sum of the individual amounts: 40 + 2000 + 100 = 2140.
If we were instead using the TOP_TIER
policy, all usage of cell-phone-minutes
would be billed at the tier 2 price (20) for a total of 2400, so the aggregate amount reported would be 2500.
Detail Mode
Sometimes it is desirable to output one USAGE
item per unit type and tier, so in this case the detail for the billing is inside each
invoice item, and the aggregate amount is computed by summing all the amounts. In order to activate this mode, one needs to set
the system property org.killbill.invoice.item.result.behavior.mode
to DETAIL
.
Each of the USAGE
items will contain the following fields:
-
quantity
: Quantity consumed for the unit (type) and on the given tier -
rate
: Therate
field normally reserved for theRECURRING
type is used to output the price of the tier
Also, the itemDetails
json field will provide some additional details:
{
"tier": 1,
"tierUnit": "cell-phone-minutes",
"tierPrice": 2,
"tierBlockSize": 1,
"quantity": 20,
"amount": 40
}
Past Usage Periods
By default the system is configured to look at the past 2 billing periods, but this can be changed by using the configuration org.killbill.invoice.readMaxRawUsagePreviousPeriod
(default=2). Let’s assume a MONTHLY subscription that was invoiced for the following periods:
-
2018-01-01 - 2018-02-01
-
2018-02-01 - 2018-03-01
-
2018-03-01 - 2018-04-01
On 2018-05-01
, the system will by default look to invoice for the period 2018-04-01 - 2018-05-01
, but it will also recompute items for the past 2 periods, 2018-03-01 - 2018-04-01
and 2018-02-01 - 2018-03-01
.
Late Usage Data:
If for some reason, there is some late usage reported in these past 2 periods, the system will include this delta. Depending on the type of usage and mode (e.g AGGREGATE
) we will see one or several USAGE
item for this period to reflect this additional charge. If the late usage is older than these past 2 periods, it is simply ignored.
Missing Usage Data:
Currently it is considered an error to delete past usage data in these past 2 periods. If this occurs, the invoicing system throws an error and prevents invoicing from happening correctly. If the late missing data is older than these past 2 periods, it is simply ignored.
One can set the system property — or per-tenant config — org.killbill.invoice.readMaxRawUsagePreviousPeriod
to 0
to ignore any past data — late usage or missing data.
Invoice Payments
Payments can be made against existing invoices, either automatically by the system or manually using our apis. By default one payment is applied to pay one invoice in full. Kill Bill also allows multiple partial payments against a given invoice. Using one payment to pay multiple invoices is not (yet) supported.
Payment in full against an invoice happens automatically provided the customer Account
has a valid default payment method. However, This behavior will be disabled under the following conditions:
-
Account
does not have a default payment method. -
Account
has been tagged with one of the following:-
AUTO_PAY_OFF
: Prevent system from making automatic payments. -
MANUAL_PAY
: Prevent system from making automatic payments because we expect those payments to happen outside of the Kill Bill system — e.g checks.
-
Anytime an Account
has a positive balance, i.e. at least one Invoice
was not fully paid, one can use our apis to issue a manual payment against such invoices. Based on what we said earlier, this situation can occur if the system was configured to not make payments automatically, or in cases where a payment was issued but failed.
The call below illustrates how to make a manual payment against an existing unpaid invoice:
curl -v \
-u admin:password \
-H "Content-Type: application/json" \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H 'X-Killbill-CreatedBy: demo' \
-X POST \
--data-binary '{
"accountId": "27cf01b3-ee14-4d7f-a63a-16ad632b7bbb",
"paymentMethodId": "7cb5362a-ca9a-4ae0-9623-381201ded137",
"targetInvoiceId": "99f91a42-a83f-4d59-b337-9df1b53f79b1",
"purchasedAmount": 200.0
}' \
'http://127.0.0.1:8080/1.0/kb/invoices/99f91a42-a83f-4d59-b337-9df1b53f79b1/payments'
Kill Bill keeps track of the mapping between invoices and payments, so that it can correctly compute the invoice balance, and also return the payment details associated with a given invoice. This mapping, InvoicePayment
, is logically part of the invoice subsystem, and is returned when invoices are fetched.
If an invoice doesn’t have a corresponding row in invoice_payments
, this means the invoice isn’t paid (because either no payment was ever attempted, or the payment attempts were unsuccessful). There are three types of InvoicePayment
: successful payment, payment followed by a refund, and payment followed by a chargeback. Each of these is described below.
Successful Payment
A successful payment against an invoice would have a single row (of type ATTEMPT):
Invoice # | Type | Payment date | Amount |
---|---|---|---|
1029 |
ATTEMPT |
2013-04-12 22:45:39 |
$20 |
Refund
A payment followed by a refund would look like this:
Invoice # | Type | Payment date | Amount |
---|---|---|---|
1029 |
ATTEMPT |
2013-04-12 22:45:39 |
$20 |
1029 |
REFUND |
2013-04-18 10:23:11 |
$-20 |
Chargeback
Finally, a payment followed by a chargeback would look like this:
Invoice # | Type | Payment date | Amount |
---|---|---|---|
1029 |
ATTEMPT |
2013-04-12 22:45:39 |
$20 |
1029 |
CHARGED_BACK |
2013-04-18 10:23:11 |
$-20 |
Payment
Overview
Kill Bill provides a core payment system that is used in subscription billing to issue payment requests against the generated invoices.
To accomodate that use case, the payment logic has been split into two pieces:
First, there is a core payment system whose role is to manage the payment states and route the operation to the correct payment plugin, which in turn interracts with the third party payment gateway. This core payment system is not specific to the subscription billing use case. It can be used also as a standalone system to provide a layer in front of various payment gateways. For an overview of the payment system in Kill Bill, please check the payment guide.
In order to support the subscription billing use case, and issue payments against existing invoices, there is a payment control plugin embedded into the Kill Bill core (see payment control plugin guide). The role of this plugin is to provide the necessary logic to coordinate the payments associated with an invoice:
-
The plugin is called before the payment system attempts to make the payment call to provide the necessary sanity, such as verifying the invoice balance, checking whether the
Account
was tagged asAUTO_PAY_OFF
, and interracting with the invoicing system to record the payment attempts. -
The plugin is then called after the payment attempt to update the invoicing system about success or failure:
-
In the case of success, this makes the invoice balance drops to zero.
-
In the the case of failure, this provides the plugin with the opportunity to schedule a payment retry.
-
Note: The plugin linking the payment view to the invoice view is not a standalone plugin; instead it is part of the core Kill Bill source code. However, it acts as a plugin since it implements the PaymentControlPluginApi. It is possible to provide a standalone plugin that would override the behavior of the default plugin, but this should only be done for advanced use cases. Extra caution would be required to not break the contract between the invoicing and payment system.
Payment Methods
A PaymentMethod
represents an abstraction to identify a way of making payments for a specific Account
. Each consumer Account
can have several payment methods to allow making payments using different schemes, such as credit cards, debit cards, or PayPal. In order to allow the system to automatically make payments against unpaid invoices, a default payment method must be specified.
The payment method really has two functions:
-
In the default use case, it allows the system to properly route the payment to the right Kill Bill plugin and to its associated third party payment gateway. Note however that the static configuration between the payment instrument — e.g the customer credit card — and the plugin can be overriden in a payment control plugin to provide payment routing capabilities.
-
It allows enough details to be tracked to make the payment. For instance if the payment method is a credit card, the system would keep track of a credit card token that can be used to issue the payment. Often, some of this information is stored inside the payment plugin.
Kill Bill also allows the user to configure a special payment method, called external payment method, to allow recording payments that occured outside of the system. For example, a customer may be invoiced through Kill Bill, and later make payment by check. The payment needs to be recorded into the system to mark the invoice as being paid and to bring its balance to zero.
A user would typically create a default external payment as shown below. Later, the returned paymentMethodId
could be used to issue external payments against invoices (see Invoice Payment section).
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey: bob" \
-H "X-Killbill-ApiSecret: lazar" \
-H "Content-Type: application/json" \
-H "X-Killbill-CreatedBy: demo" \
-X POST \
--data-binary '{"pluginName":"__EXTERNAL_PAYMENT__","pluginInfo":{}}' \
"http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?isDefault=true"
Payment Retries
If a payment fails, the plugin may attempt a payment retry. There are two system properties that control the payment retry mechanism:
-
Upon PAYMENT_FAILURE — when the payment plugin returns an ERROR status --, the payment system will look at the property org.killbill.payment.retry.days, and possibly schedule some retries based on that value. By default, this property is set with a default value of 8,8,8, which means that a first retry would happen 8 days after the intial failure, and then if the first retry attempt failed, another attempt would be scheduled 8 days later and then finally a last one 8 days after that. If the last attempt fails, the payment remains in the PAYMENT_FAILURE state.
-
Upon PLUGIN_FAILURE — when the payment plugin returns a CANCELED status --, the payment system will look at the property org.killbill.payment.failure.retry.start.sec, and possibly schedule some retries based on that value. By default, this property is set with a default value of 300, which means that the payment would be scheduled to be retried one time 300 seconds — or 5 minutes — after the failure. PLUGIN_FAILURE is often linked to transient errors from third party gateways, so it makes sense to retry those fairly soon after the initial failure was seen. But of course, this all depends on the use case.
Payment retries in Kill Bill are implemented as payment transaction retries: For each retry attempt, the system will create a new PaymentTransaction
associated with the same Payment
object. Since the paymentMethodId
is defined at the Payment
level, it means that the same paymentMethodId
will be used for each retry. If the goal is to retry with a new payment method, then one needs to create a new Payment
associated with the different payment method. If there are ongoing retries scheduled, it is possible to cancel those but this is more for cleanliness, because once a payment has been successful, any other retry would be aborted; the system ensures that there cannot be any double payment.
Overdue
Overview
Kill Bill offers an Overdue
feature, also referred to as Dunning, which is required when users don’t pay their bills. In those cases, the merchant needs to take some action and so the feature must be customizable. Note that the Entitlement
and Overdue
modules in Kill Bill are tied to each other and are there to manage the customer experience regarding her subscription(s):
-
The
Entitlement
module defines the behavior of the system when the user starts or cancels a subscription or makes some change in an existing subscription. It controls the level of service received by the user (from no service at all to full service) after such an operation occurs. -
The
Overdue
module is in charge of altering the customer experience when payments are not met. This alteration may include some degradation or even cancelation of the service. The overdue state is defined at the account level, which means that if a user has multiple subscriptions, and an invoice associated with one of them has not been paid, the behavior of the system with regard to the overdue state will be global for all subscriptions.
The Overdue module in Kill Bill relies on a configuration file which drives its behavior. The configuration can be specified at the tenant level, similarly to the catalog, or it can be specified globally for the system using the org.killbill.overdue.uri
system property (e.g org.killbill.overdue.uri=file:///<path>/overdue.xml
). This property specifies an overdue configuration file overdue.xml
. For details on this file see Overdue System. If no file is specified, default values will be used.
The Overdue module listens to payment events, then changes the overdue state for an account to the appropriate state based on the configuration. Whether the payment was a failure or not, the Overdue module will recompute the state associated with the account and potentially make the transition to another state.
Configuration
The overdue configuration contains a list of the various states that a customer’s account may go through if the customer does not pay. Each state has a name
and a condition
which is evaluated by the Overdue
module. Currently the condition to transition to a given state is based on the properties below, and the system will evaluate to true if all the parts of the conditions are true:
-
numberOfUnpaidInvoicesEqualsOrExceeds
-
totalUnpaidInvoiceBalanceEqualsOrExceeds
-
timeSinceEarliestUnpaidInvoiceEqualsOrExceeds
-
responseForLastFailedPaymentIn
: (Not implemented) -
controlTagInclusion
-
controlTagExclusion
Additionally, the definition of an overdue state will also specify some ways to alter the behavior of the system:
-
subscriptionCancellationPolicy
: Specifies whether or not to cancel the subscriptions associated with the account (and the cancellation policy that should be used). The choices are (NONE
,IMMEDIATE
,END_OF_TERM
). -
blockChanges
: Specifies whether the customer is allowed to make any plan change on his subscriptions. -
disableEntitlementAndChangesBlocked
: The name is a bit misleading; it specifies whether the subscriptions are being paused, which means service (entitlement) will be disabled and billing will also be disabled. If the overdue state clears, both entitlement and billing would resume at the time of the clearance.
One can add an externalMessage
which can be retrieved by plugins listening to Overdue events, and displayed to the user.
Finally there is an additional property autoReevaluationInterval
that tells the system when to re-evaluate the state when nothing happens in the system. When an account transitions to one of the overdue states specified by the xml file overdue.xml
, two things can happen:
-
The user makes a payment OR the system retries previously failed payments
-
No payment attempt is being made
In the first case, the Overdue system will detect that a payment occurred and it will recompute the state, transitioning to a new state if required. In the second case, however, since there was no trigger, we need a way to tell the overdue system to re-evaluate the state every so often so it can advance into the next state if required. That is what the autoReevaluationInterval
property is about.
If you need an xsd file, you can find one here or generate one using the overdue xsd-tool:
curl -O 'http://search.maven.org/remotecontent?filepath=org/kill-bill/billing/killbill-overdue/x.y.z/killbill-overdue-x.y.z-xsd-tool.jar'
java -jar killbill-overdue-*-xsd-tool.jar schema.xsd
Tags
Kill Bill offers the ability to tag resources (account, invoice, payment, subscription, etc.) in the system. There are two main types of tags:
-
User tags
: These tags are not interpreted by the system; they are a convenient way for admins or third party systems to annotate specific existing resources. For instance, the support team could tag account resources associated with a specific customer to group them. -
Control tags
: These tags modify the behavior of the system. The following control tags can be associated with an account:-
AUTO_PAY_OFF: When this tag is set, the system will not attempt to trigger automatic payments from this account after invoices have been generated. When the tag is removed, the system will immediately attempt to issue the payments that were not made.
-
AUTO_INVOICING_OFF: When this tag is set, the system will not attempt to invoice the customer. When the tag is removed, the system will immediately attempt to issue invoices for the account.
-
OVERDUE_ENFORCEMENT_OFF: When this tag is set, the system will not attempt to change the account into an overdue state regardless of any potential failed payments. When the tag is removed, the system will immediately recompute the current overdue state.
-
MANUAL_PAY: When this tag is set, the system will not attempt to trigger automatic payments after invoices have been generated. The intent of this tag is to allow the customer to make his payment outside of Kill Bill.
-
TEST: This tag is used by the analytics plugin to prevent this account from being included in the set of accounts.
-
PARTNER: This tag is used by the analytics plugin so the account can be interpreted differently.
-
-
The following control tag is associated with a specific invoice:
-
WRITTEN_OFF: This tag indicates that the system should ignore the balance for this invoice.
-
Glossary
Account - An object representing a customer account. It contains details about the customer such as name, address, email address, phone number, etc.
Bundle - A collection of subscriptions associated with a single service instance. For example, a customer might have a base subscription for her phone plus an addon that provides cheap international dialing. Because both Subscriptions are associated with the same phone, they are collected into a single Bundle. An account may own several Bundles, each with one or more Subscriptions.
Catalog - A description of the Products, Plans, Price Lists and Rules that are being made available to customers. A catalog lets Kill Bill know what is being offered for sale and how much to charge for it.
Payment Method - A record of the details required for Kill Bill to trigger a payment. Payment Methods represent things like credit cards, debit cards, or PayPal accounts. Each Account can have many Payment Methods and at most one Default Payment Method. Note that much of the representation of a Payment Method is plugin-specific and is actually stored by the Payment Plugin itself.
Plan - A Catalog object that defines how a Product is to be paid for. Plans can have multiple phases (e.g. trial, discount, evergreen). The phase specifies the frequency of payment and the prices in multiple currencies. Each phase can have fixed and recurring prices associated with it. Each Product can have multiple Plans specifying different ways that the Product can be purchased (e.g. a monthly Plan and an annual Plan).
Price list - A collection of Plans that might be associated with a particular program (e.g. an affiliate program or a discount program). A Plan can be in many Price Lists. There must be a default Price List that is used when no Price List is specified. When a Subscription changes Plans, Catalog Rules can be used to determine which Price List the new Plan should use.
Product - A product or service that the customer buys.
Subscription - A contract that associates an account with a Plan and a specific start date. The Subscription will trigger automated payments based on the terms of the Plan.
Tag - A property that can be added to Accounts, Bundles or Subscriptions. There are two kinds of Tags: System Tags and User Tags. System Tags can impact the behaviour of the system. Examples include AUTO_PAY_OFF or AUTO_BILLING_OFF. User Tags are informational only, and can be created through the admin UI. User Tags are used to identify collections of Users, Subscriptions or Bundles so that they can easily be found or reported on later.