This version of Kill Bill is not supported anymore, please see our latest documentation

Introduction

Both our Subscription Billing and Payments platform user guides have 5 minutes tutorials to get you started interacting with Kill Bill.

This tutorial is different however: it will help you put all of the pieces together and work through a real-world scenario, so you understand how to integrate Kill Bill with your application.

Scenario

Let’s assume you want to build a site similar to Amazon Prime, i.e. an e-commerce website which offers a shopping cart and where paying subscribers have extra benefits (discounts, free shipping, etc.). You want to accept both credit cards and PayPal as means of payment.

Note that we won’t go into the details of building the actual website, we will assume you already have a front-end (Rails app, JSP webapp, etc.). Kill Bill will handle all subscriptions and payments as a separate service, and your application will communicate with Kill Bill over HTTP APIs.

Requirements

We will assume:

  • You have Ruby 2.1+ or JRuby 1.7.11+ installed. This requirement is only to simplify the installation using KPM. Alternatively, you can install Kill Bill manually by following the userguide

  • You have cURL installed. This is only to be able to run the examples from this tutorial. In practice, your application will use one of our client libraries

  • You have MySQL installed and have created a killbill database

Setup

Payment gateways setup

To accept credit cards, we will integrate with Stripe: they offer free sandbox accounts and provide a nice dashboard to follow what’s going on. Choosing your payment processor is critical however, you need to make sure it offers the features you need (international payments, etc.) while minimizing your costs. Luckily, there are thousands of vendors available and Kill Bill can integrate with pretty much any of them, so make sure to do your research.

Another word of caution is regarding PayPal: the setup is a bit complicated and their UI glitchy unfortunately. You can follow along this tutorial even if you don’t have yet your credentials (you just won’t be able to test payments end-to-end).

Stripe

PayPal

  • Create a free account at paypal.com

  • Go to your Dashboard and click Create Account (You need both a Personal and one Business account). The Business account is for the merchant that will receive the money and the Personal account is for the customer that will purchase the subscription.

  • Login to the sandbox using the Personal account credentials and add some money

You then need to contact support so they can enable recurring payments on your sandbox:

  • Go to PayPal Technical Support

  • Create a ticket and ask to "Enable reference transactions for the Sandbox account XXXXX". Replace XXX with the API username of the Business test account you created (to see the username, click on Profile in the dashboard under the email address of the account, then click on the API credentials tab)

This process can take up to 48 hours. In the meantime, while you will be able to test one-time purchases, you won’t be able to test recurring transactions in PayPal.

Initial setup

MySQL

As stated in the requirements, we’re assuming you already have MySQL installed with a killbill database. You need to populate the database with the tables for Kill Bill, and its plugins.

Assuming the server is located at 127.0.0.1 and the username/password to connect to it are killbill/killbill, run:

curl http://killbill.io/wp-content/uploads/2014/11/killbill-0.12.0.ddl | mysql -h 127.0.0.1 -ukillbill -pkillbill killbill
curl https://raw.githubusercontent.com/killbill/killbill-stripe-plugin/master/db/ddl.sql | mysql -h 127.0.0.1 -ukillbill -pkillbill killbill
curl https://raw.githubusercontent.com/killbill/killbill-paypal-express-plugin/master/db/ddl.sql | mysql -h 127.0.0.1 -ukillbill -pkillbill killbill

Tomcat

We will use the Tomcat container to run Kill Bill as a Web application. If you are not familiar with Java containers, don’t worry, the process is pretty straightforward:

  • Download the Tomcat container here

  • Un-tar the archive. We will assume it is at /var/tmp/tomcat in the rest of this tutorial

  • Remove all files and directories under webapps/

  • Create a configuration file for Kill Bill: mkdir -p conf/Catalina/localhost && echo '<Context></Context>' > conf/Catalina/localhost/ROOT.xml

The final step is to point it to your MySQL installation. Add this to conf/catalina.properties, updating the parameters as necessary (note that Kill Bill has two JDBC pools, one for the core and one of OSGI plugins):

org.killbill.billing.osgi.dao.url: jdbc:mysql://127.0.0.1:3306/killbill
org.killbill.billing.osgi.dao.user: killbill
org.killbill.billing.osgi.dao.password: killbill
org.killbill.dao.url: jdbc:mysql://127.0.0.1:3306/killbill
org.killbill.dao.user: killbill
org.killbill.dao.password: killbill

Kill Bill installation

We will use KPM (the Kill Bill Package Manager) to simplify the installation of Kill Bill and its plugins.

Create a kpm.yml file with the following content:

killbill:
  version: 0.12.1
  webapp_path: /var/tmp/tomcat/webapps/ROOT.war
  plugins_dir: /var/tmp/bundles
  plugins:
    ruby:
      - name: paypal-express-plugin
        version: 1.8.1
      - name: stripe-plugin
        version: 1.0.0

This instructs kpm to install Kill Bill version 0.12.1 in the Tomcat webapps directory, as well as two payment plugins, one for Stripe and one for PayPal. To start the installation, run:

kpm install kpm.yml

Once KPM is done, you should see the war at /var/tmp/tomcat/webapps/ROOT.war as well as various files and directories under /var/tmp/bundles.

Plugins are installed under /var/tmp/bundles/plugins. You should see one sub-directory per plugin. If you work with Ruby, the directory structure should be familiar, as it is simply a gem cache. If you don’t, don’t worry. Just know that each plugin is independent and has all of its dependencies, hence the large number of files and directories.

The /var/tmp/bundles/platform/ directory is used for non Kill Bill specific OSGI plugins. For convenience, it installed a recommended set of useful plugins to interact with OSGI, enhance logging, etc. If you don’t know what OSGI is, don’t worry about it, these plugins will just make your life easier down the line. There is one important file in that directory however: /var/tmp/bundles/platform/jruby.jar. This file makes it possible for Kill Bill to run Ruby plugins. While you could delete all other files in that directory, without jruby.jar, none of the payment plugins installed will start!

Stripe setup

Configure the Stripe plugin by create the configuration file at /var/tmp/bundles/plugins/ruby/killbill-stripe/1.0.0/stripe.yml (replace your credentials accordingly):

:stripe:
  :api_secret_key: 'sk_test_aaaabbbbccccdddd'
  :test: true

PayPal setup

Configure the Stripe plugin by create the configuration file at /var/tmp/bundles/plugins/ruby/killbill-paypal-express/1.8.1/paypal_express.yml (replace your credentials accordingly):

:paypal_express:
  :signature: 'your-paypal-signature'
  :login: 'your-username-facilitator.something.com'
  :password: 'your-password'
  :test: true

:database:
  :adapter: 'jdbcmysql'
  :jndi: 'killbill/osgi/jdbc'
  :connection_alive_sql: 'select 1'
  :pool: 25

Testing

That’s it! Kill Bill should be ready to use. Let’s try to start Kill Bill:

./bin/catalina.sh run

One the startup sequence is done, you should see Kill Bill running at http://127.0.0.1:8080/index.html.

Test your installation by creating a tenant:

curl -v \
     -X POST \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-CreatedBy: admin' \
     -d '{"apiKey": "bob", "apiSecret": "lazar"}' \
     "http://127.0.0.1:8080/1.0/kb/tenants"

Tenants lets you namespace accounts and all associated data (subscriptions, invoices, payments, etc.) in Kill Bill. This is especially useful for testing: create a new tenant, try a few things out and when you are done, delete the data associated with this tenant (the rest of the data will be preserved).

At this point, we’re ready to integrate Kill Bill with your application.

Shopping cart integration

In your website, we assume you have a shopping cart module: users can add items to their basket and when they are ready, go to the checkout page. This page will present various payment options (credit card form and PayPal button), as well as display their payment methods on file (previously used credit cards or linked PayPal accounts).

Creating accounts

For simplicity, we will assume that users going to your site have to create an account in your system (you could work around this limitation using sessions). When they create their account, you will need to create a mirrored account in Kill Bill. This will let you do things like retrieve all payments for a given user, etc.

To create an account:

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 '{"name":"John Doe","email":"[email protected]","externalKey":"john-doe-1234","currency":"USD"}' \
     "http://127.0.0.1:8080/1.0/kb/accounts"

Notes:

  • The externalKey should map to the unique id of the account in your system

  • There are many more fields you can store (phone number, address, etc.), but the above is the minimal set

The call above will return a Location header containing the Kill Bill account id (uuid). In the following curl commands, you’ll need to replace the account id with yours.

Storing payment methods

At some point, the user will need to store his credit card information and/or his PayPal account. This can happen on a settings section of your website, or during the checkout flow.

This step is probably the most difficult one, as it is payment processor specific.

Stripe

Handling credit card information is regulated by the PCI-DSS standard. Fortunately, Stripe lets your work around these requirements by providing a special form. Users will use this form to securely store their card into Stripe servers, while Stripe will give you a token you will use to charge these cards.

For more details on the integration, checkout the stripe.js documentation.

When the Javascript call returns from Stripe, it will contain the token that needs to be stored in Kill Bill:

curl -v \
     -X POST \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     -H 'X-Killbill-CreatedBy: creator' \
     --data-binary '{
       "pluginName": "killbill-stripe",
       "pluginInfo": {
         "properties": [
           {
             "key": "token",
             "value": "t3GER3BP3JHLASZe"
           }
         ]
       }
     }' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?isDefault=true"

This will create a new payment method and set is as the default for the account.

PayPal

The PayPal flow is a bit different. You first need to tell PayPal you are going to create a token:

curl -v \
     -X POST \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     -H 'X-Killbill-CreatedBy: creator' \
     --data-binary '{
       "kb_account_id": "13d26090-b8d7-11e2-9e96-0800200c9a66",
       "currency": "USD",
       "options": {
         "return_url": "http://www.google.com/?q=SUCCESS",
         "cancel_return_url": "http://www.google.com/?q=FAILURE",
         "billing_agreement": {
           "description": "Your subscription"
         }
       }
     }' \
     "http://127.0.0.1:8080/plugins/killbill-paypal-express/1.0/setup-checkout"

Kill Bill will return a 302 Found on success. The customer should be redirected to the url specified in the Location header, e.g. https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-20G53990M6953444J.

Follow the link to log to the paypal site: On the PayPal site, the user will be guided through the approval process to create a token for your website.

Once that step is completed, the customer comes back from the PayPal flow, you can now create the payment method in Kill Bill by specifyfing the token that was returned in the setup-checkout step (EC-20G53990M6953444J). Note that this token is now associated to the customer that was redirected to Paypal and that accepted the agreement.

curl -v \
     -X POST \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     -H 'X-Killbill-CreatedBy: creator' \
     --data-binary '{
       "pluginName": "killbill-paypal-express",
       "pluginInfo": {
         "properties": [
           {
             "key": "token",
             "value": "EC-20G53990M6953444J"
           }
         ]
       }
     }' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?isDefault=true"

Processing payments

While storing a payment method is payment processor specific, triggering payments isn’t (Kill Bill is hiding the complexity for you). When the user clicks "buy" on your checkout page, perform the following call (update the amount accordingly):

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" \
     --data-binary '{"transactionType":"PURCHASE","amount":"10","currency":"USD"}' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/payments"

That’s it! The call will synchronously go to Stripe or PayPal, depending on the default payment method on the account, and perform the payment.

If you want to display payment methods information on the checkout page, you can retrieve them via:

curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?pluginInfo=true"

This is useful if you want to let the user override the payment method to use during checkout. In that case, you can pass the query parameter paymentMethodId to the purchase call above.

Subscriptions integration

Now that your users are able to purchase their products, we want to offer a buy-up subscription option, and offer free shipping to subscribed users. For simplicity, we will assume that we offer a single Standard plan, at $24.95 per month.

Creating the catalog

Plans are defined in an xml configuration file. This file is really powerful and offer various options for handling trials, add-ons, upgrades/downgrades, etc. For more details on its features, read the Subscription Billing user guide.

For this tutorial, here is what the catalog looks like:

<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
    <effectiveDate>2014-11-01T00:00:00+00:00</effectiveDate>
    <catalogName>ShoppiShop</catalogName>
    <recurringBillingMode>IN_ADVANCE</recurringBillingMode>
    <currencies>
        <currency>USD</currency>
    </currencies>
    <products>
        <product name="Standard">
            <category>BASE</category>
        </product>
    </products>
    <rules>
        <changePolicy>
            <changePolicyCase>
                <policy>IMMEDIATE</policy>
            </changePolicyCase>
        </changePolicy>
        <changeAlignment>
            <changeAlignmentCase>
                <alignment>START_OF_BUNDLE</alignment>
            </changeAlignmentCase>
        </changeAlignment>
        <cancelPolicy>
            <cancelPolicyCase>
                <policy>IMMEDIATE</policy>
            </cancelPolicyCase>
        </cancelPolicy>
        <createAlignment>
            <createAlignmentCase>
                <alignment>START_OF_BUNDLE</alignment>
            </createAlignmentCase>
        </createAlignment>
        <billingAlignment>
            <billingAlignmentCase>
                <alignment>ACCOUNT</alignment>
            </billingAlignmentCase>
        </billingAlignment>
        <priceList>
            <priceListCase>
                <toPriceList>DEFAULT</toPriceList>
            </priceListCase>
        </priceList>
    </rules>
    <plans>
        <plan name="standard-free">
            <product>Standard</product>
            <finalPhase type="EVERGREEN">
                <duration>
                    <unit>UNLIMITED</unit>
                </duration>
                <fixed></fixed>
            </finalPhase>
        </plan>
        <plan name="standard-monthly">
            <product>Standard</product>
            <finalPhase type="EVERGREEN">
                <duration>
                    <unit>UNLIMITED</unit>
                </duration>
                <recurring>
                    <billingPeriod>MONTHLY</billingPeriod>
                    <recurringPrice>
                        <price>
                            <currency>USD</currency>
                            <value>24.95</value>
                        </price>
                    </recurringPrice>
                </recurring>
            </finalPhase>
        </plan>
    </plans>
    <priceLists>
        <defaultPriceList name="DEFAULT">
            <plans>
                <plan>standard-free</plan>
                <plan>standard-monthly</plan>
            </plans>
        </defaultPriceList>
    </priceLists>
</catalog>

While each section is described in greater detail in the user guide, here are the important points to notice:

  • recurringBillingMode is set to IN_ADVANCE, meaning we will invoice at the beginning of a billing period

  • We have defined a single Standard product. The category is BASE (as opposed to ADD_ON)

  • There are two plans defined: standard-free and standard-monthly. We could have just defined the latter, but we will make free users subscribe to the free plan. This is useful for reporting for example (to track how long it took to upsell them, etc.)

  • There is no trial period

Creating and retrieving subscriptions

Set the following property (in conf/catalina.properties) and restart Kill Bill (make sure to update the path to your catalog):

org.killbill.catalog.uri=file:///var/tmp/catalog.xml

Let’s try to subscribe a user to the Standard plan. This is the call that will need to be triggered from the website, when the user chooses the premium plan on the subscription checkout page (we assume the user has already an account and payment method on file, see the previous section otherwise):

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 '{"accountId":"0c9548f0-3c8f-41e8-abe2-966510076daf","productName":"Standard","productCategory":"BASE","billingPeriod":"MONTHLY","priceList":"DEFAULT"}' \
     "http://127.0.0.1:8080/1.0/kb/subscriptions"

Because there is no trial period and billing is performed in advance, Kill Bill will have automatically billed the user for the first month.

To view the invoice:

curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     "http://127.0.0.1:8080/1.0/kb/accounts/0c9548f0-3c8f-41e8-abe2-966510076daf/invoices"

To view the payment:

curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     "http://127.0.0.1:8080/1.0/kb/accounts/0c9548f0-3c8f-41e8-abe2-966510076daf/payments"

Kill Bill will now automatically charge the user on a monthly basis. You can estimate the amount which will be billed at a future date (replace the targetDate parameter with a date in the future):

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 \
     "http://127.0.0.1:8080/1.0/kb/invoices/dryRun?accountId=0c9548f0-3c8f-41e8-abe2-966510076daf&targetDate=2014-12-21"

Premium feature example: applying 10% discount at checkout

We are able to charge customers one a one-time basis, and subscribe them to the premium plan. We now need to bring it together: as an example, we will apply a 10% discount in the shopping cart, when users are premium subscribers.

In the basket view, retrieve the list of bundles the user is subscribed to:

curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     "http://127.0.0.1:8080/1.0/kb/accounts/0c9548f0-3c8f-41e8-abe2-966510076daf/bundles"

The subscription list will show the cancellation status: cancelledDate. If it’s null or in the future, the subscriber is still a paying customer, in which case you can apply the 10% discount.

Conclusion

In this tutorial, we’ve shown you how to leverage the basic features of the Kill Bill platform, how to provide recurring and one-off billing, as well as integrate with various payment processors. Kill Bill has many more features to offer, make sure to read the user guide.

Next steps: exercises for the reader

If you want to continue the tutorial, here are some next steps:

  • Setup Kaui. Kaui is the Kill Bill Administrative UI. It can be used as an internal tool to visualize subscriptions, handle refunds, add credits, perform payments, etc. (Hint: KPM can handle it for you)

  • Configure the overdue system. What happens when premium subscribers don’t pay?

  • Setup the Analytics plugin to create revenue dashboards and monitor your MRR.

  • Defer authorize and capture: if you are shipping physical goods, you are required to defer capture only when the product ships.

  • Add a second plan, with a discounted yearly pricing and try to upgrade/downgrade users between plans.