Kill Bill payment guide

This is the reference guide to get started with Kill Bill Payments Platform.

Introduction

Kill Bill Payments Platform is designed to offer a single payment API for any type of payment gateway, processors, bank,…​ and to support any kind of payment flows. It is typically used to charge customers in eCommerce Shopping Card type flows.

Requirements

We will assume:

You already went through the Getting started tutorial and have MySQL, Kill Bill and Kaui setup and running in Docker containers

You have a tenant configured with API key bob and API secret lazar

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

Overview

Payment Abstractions

Kill Bill has a payment subsystem which offers several APIs:

payment and refund APIs for recurring billing

direct payment APIs for one-off charges

The former set of APIs is used by the core billing engine to charge for subscriptions, and by Kaui (the Kill Bill Admin UI) to handle refunds, chargebacks, adjustments, etc. for invoices and payments associated with such subscriptions.

The latter set can be used to trigger payments (auth, capture, credit, refund, etc.) by your e-commerce application (e.g. shopping cart). It also offers helpers to create payment forms and redirect URLs in case of hosted payment pages. It is independent of any subscriptions or invoices and is used solely to make payments.

Kill Bill is a generic platform to build billing and payment infrastructures and as such, it is agnostic of payment gateways. However, it provides a framework to register payment plugins, which in turn implement gateway specific APIs. Those payment plugins must be OSGI compliant plugins. They can be written either in:

java; in which case they are just a standard OSGI java jar which must register a service implementing the PaymentPluginApi

ruby; in which case they must use the killbill gem which provides a jruby bridge between java and ruby. Those plugins must inherit the Payment class to provide the specific plugin code functionality

The main reason to provide a way to write ruby payment plugins is to be able to reuse the Active Merchant gem. We even have a generator to help you generate a payment plugin from an Active Merchant implementation.

Check the wiki page Payment Plugins for a community-supported list of already written payment plugins.

The Kill Bill payment code will detect all the payment plugins registered in the system and decide which plugin to use when a charge, refund, …​ operation needs to happen. The dispatching is based on the payment methods associated with each account. By default, the model is to attach a default payment method to each account: that payment method will have a link that points to a specific plugin to use. For instance, one account could have a Paypal payment method that would point to the Paypal plugin. Additionally, you can also override the payment method to use on a per payment call. The figure below shows the relashionship between a Kill Bill Account, its various PaymentMethods, each of which points to a given Kill Bill plugin, which itself is in charge to interact with a third party payment gateway.

By default Kill Bill does not come configured with any payment plugins except for the built-in EXTERNAL_PAYMENT, which is used to track payments which occurred outside of Kill Bill. A typical example would be for when a customer pays by check and we want to make sure the invoice balance is set to 0 after receiving the check. A user, represented in Kill Bill as an account can add as many payment methods as required, and each of those will identify a specific plugin that Kill Bill will use when making payments.

Payment States

Initially a client of the api can make either an authorization, a purchase, or a credit call (all other operations such as refund would require an initial payment to have already existed).
That initial operation will create a Payment and an initial PaymentTransaction.
The user can then submit additional requests for the same payment (capture, refund, …​) and each of those calls will result in additional PaymentTransaction attached to the same payment.
The payments have a state which will drive the set of possible subsequent operations available. For instance, it is possible to make a capture call against a payment in a state AUTH_SUCCESS but it is not possible to make such an operation against a payment in an AUTH_ERRORED state.
The set of payment state transitions are configured in an xml file and the Kill Bill payment subsystem is in charge to enforce the transitions. The following diagram below shows all the possible transitions:

In addition to the payment state transitions, each PaymentTransaction has a status to reflect the result of the operation. The PaymentTransaction status depends on the plugin result and it can be summarized below:

The payment transaction went through but failed (e.g insufficient funds)

CANCELED

PLUGIN_FAILURE

{AUTH,CAPTURE,..}_ERRORED

502 - Bad Gateway

The payment transaction did not happen (e.g unable to connect to the provider, error in plugin, etc)

UNDEFINED, timeout or any exception

UNKNOWN

{AUTH,CAPTURE,..}_ERRORED

503 - Service Unavailable
504 - Gateway Timeout

The payment transaction may or not have succeeded, manual review needed

Note that the first 3 cases are normal cases but the last 2 are errors that are unrelated to the user being able to make the payment operation:

in the case of a hard plugin failure (CANCELED result code), the gateway was probably down and the payment wasn’t attempted: there is no attempt to fix those.

in the case of a plugin timeout (or UNDEFINED result code), the operation might actually have completed; Kill Bill will run a background task to detect those cases and will query the plugin to verify if the state is actually known and when it is, it will update the transaction status and move the payment to its appropriate state. If the plugin cannot tell if the payment went through, the transaction will stay in an UNKNOWN state. It is advisable to check that those are rare instances and fix the data appropriately (by checking manually the status in the gateway for example).

If a payment is aborted by a control plugin, a payment attempt row is recorded with a state of ABORTED (no payment nor payment transaction is created). Kill Bill will return a 422 HTTP code.

Payment Flows

Payment flows overview

Kill Bill supports two main payment flows, referred to as Hosted Payment Pages (or HPP) and as Gateway integration:

A HPP flow is when the payment is completely outsourced, either by redirecting the user to a third-party website or by hosting a form or an iframe, that submits the information to a third-party website

A Gateway integration flow is when the customer doesn’t leave your website and Kill Bill processes the payment directly by calling a gateway API

For a concrete example on how the two flows can be implemented, take a look at our Adyen demo.

Merchants Site: customer facing web site which receives the order and shields the payment system (i.e. Kill Bill)

Payments: the payment system (i.e. Kill Bill and its specific payment plugins which interact with the payment providers) offering APIs for the various flows

Payment Provider: also called Payment Service Provider (PSP), Payment Gateway or simply Gateway, this is the entity that will process the payment

Access Control Server (optional): in the case of 3D-Secure checkout, the user is redirected to some third party entity to enter custom information that will validate whether he can pursue with the payment flow

Hosted Payment Page flow

During an HPP flow, the customer enters his payment method information (either on the main Merchants Site or a third-party site) and then submits a form containing that information to make the payment. The information required to present the user with a payment form (specific form fields or URL where the form is hosted) is obtained by calling the buildFormDescriptor API.

The result of the API call will depend on the type of HPP integration:

If the payment form is hosted on your own website (but the form data will be sent to a third-party website), the response will list the exact fields to set, such as required visible fields (the names will vary depending on the gateway, for instance some expect a Sum field instead of amount) and required hidden fields (e.g. merchantId value). For PayPal Payments Standard Buttons for example, the API would return the values of the fields cmd, hosted_button_id and submit. The browser submits the payment information to the payment provider, which then redirects the customer to a landing page upon success or failure.

If the payment form is completely hosted on a third-party website, the response will contain a URL to redirect the user to. This URL can be generic or unique (generated by the payment plugin either by submitting the order information to the gateway or by constructing the special URL via query parameters). For Adyen HPPs for example, the API would return a url like https://live.adyen.com/hpp/select.shtml. The browser is redirected to the payment provider website for the customer to complete the payment before being redirected back to a landing page upon success or failure.

Note that after calling buildFormDescriptor, the payment may or may not exist in Kill Bill: this will depend on the plugin. If it does however, it will be most likely in a PENDING state.

Here are a few common scenarii:

the HPP provider doesn’t provide an API to retrieve the state of the payment, nor sends notifications: the only way to record the payment is when the user is redirected to the Merchants Site. In that case, buildFormDescriptor can simply return the data to create the form and/or redirect the user without creating any payment. When the user completes the payment and is redirected back to the site, the Merchants Site will need to record the payment explicitely by calling the createPurchase API. Alternatively, if you want to keep track of abandoned purchases, the plugin could create a payment in a PENDING state during the buildFormDescriptor call. After the redirect, the Merchants Site will still call the createPurchase API to complete the payment, but will pass the paymentId returned by the previous buildFormDescriptor call.

Figure 1. Payment created during the redirect

Figure 2. Pending payment created during the buildFormDescriptor call, completed during the redirect

the HPP provider provides an API to retrieve the state of the payment but does not send notifications. In this case, the URL constructed during the buildFormDescriptor call is most likely unique, and contains enough information for the plugin to poll the provider for the payment status. During the buildFormDescriptor call, the plugin will need to create a PENDING payment. Kill Bill will automatically poll the plugin calling the getPaymentInfo API, which should query the provider for the latest payment status. Example: Boleto with PayU Latam.

Figure 3. Pending payment created during the buildFormDescriptor call, completed by polling getPaymentInfo

the HPP provider doesn’t provide an API to retrieve the state of the payment but does send notifications. In this case, buildFormDescriptor can simply return the redirect URL without creating a payment, which will be created when the notification is received. Similarly to the first case above, you could create a PENDING payment if you want to track abandoned purchases, just make sure that the plugin has enough metadata to reconcile the notification with the payment. When the notification is received, either use the notifyPendingTransactionOfStateChanged Kill Bill API to transition the payment, or wait for Kill Bill to poll the plugin via the getPaymentInfo API. Example: any HPP provided by Adyen.

Figure 4. Payment created when receiving a notification from the provider

Figure 5. Pending payment created during the buildFormDescriptor call, completed when receiving a notification from the provider

The conceptual flow below shows a 3D-Secure variation of the previous flows. The main difference is that prior redirecting the browser to the landing page, it is first redirected to the access control server where the user can enter custom information.

Figure 6. Hosted Payment Page 3D-Secure variation

Gateway Integration flow

For gateway integrations, the entry point for any payment is either the createAuthorization (to authorize a credit card), createPurchase (to charge a payment method, for example authorizing and capturing a credit card, to initiate an ACH transfer, to withdraw money from a Bitcoin wallet, etc.) or createCredit (to deposit money on a payment method, without any reference to a previous payment) APIs. The payment state will be in *_INIT state before calling the plugin.

Usually, transactions end up in a terminal state right away as most gateways provide synchronous APIs. However, depending on the payment method, the plugin can choose to set the status to PENDING. For example, this is the case for 3D-Secure transactions (until the payment is verified by the issuer after redirecting the user), for direct debit transfers (e.g. ACH, which take usually a couple of days to be acknowledged), or for Bitcoin transfers (until the transaction is confirmed by the blockchain). Additionally, some gateways don’t always provide synchronous responses (e.g. when capturing funds using Adyen), in which case the plugin has to rely on asynchronous notifications to transition the payment into a terminal state.

Before any payment operation can occur, the user must first enter his payment information. In Kill Bill, this translates into creating a PaymentMethod. When dealing with credit card information specifically, merchants have to keep the data into a PCI compliant environment (often handled by the gateway): this process requires tokenization of the PAN, so that the payment system only handles the token, which is stored at the plugin level and passed to Kill Bill as a plugin property. Take a look at our Stripe demo for a concrete example.

Note that the creation of the Kill Bill payment method is not represented in the flows below: it can happen either in a prior step or during the payment using one of our combo payment call. Usually, the user is prompted with a form to enter his payment method information, and then the payment is initiated using one of the createAuthorization or createPurchase APIs. Kill Bill will connect to its payment plugin which in turn will contact the gateway to perform the required operation. Upon success/failure, the user is redirected to a landing page.

Figure 7. Gateway integration (direct payment API)

If 3D-Secure is enabled, the payment (e.g. authorization) is split into two phases:

The merchant site starts with an authorize call; if enough information is supplied to the gateway and if the payment method is 'registered' as being 3D-Secure, the gateway will return a (gateway) specific status so that the user can be redirected to the access control server to complete the flow

The user may then enter its specific information on the access control server, and upon success it is then redirected to the merchant site that will complete the authorize phase

API Overview

Plugin Properties

In the sections below, we are presenting APIs to manage payment methods and payments operations. Those APIs have been built to be as generic as possible. Because each plugin/gateway has its own specificities, you can pass extra data by using plugin properties:

For each API, one can specify custom properties by using query parameters — those query parameteres should be URL encoded

Kill Bill will deserialize the query parameters and pass them straight to the plugin

This mechanism allows to pass information from the client of the API to the plugin, while being opaque to Kill Bill; for instance, in order to specify the following two plugin properties:

The mechanism also works for receiving information back from the plugin; the plugin can return a piece of json that will be embedded in the json response; for instance, the plugin could return a specific key:

This call will return a 201 Location header containing the id associated with the newly created account. The rest of this document will assume this id is 268983f2-5443-47e4-a967-b8962fc699c5, make sure to update your commands accordingly.

This will create a default payment method associated with our account and the EXTERNAL_PAYMENT plugin. The pluginInfo fields are specific to the plugin and can be seen as a contract between the client of the API and the plugin itself (opaque to Kill Bill). For example, to add a payment method stored in PayPal, the PayPal Express plugin expects a field named token, with the value of the Paypal BAID.

You can add as many payment methods as needed to a given account (across one or multiple plugins). You can specify for each payment call the payment method to use, or leave it blank to use the default.

Each payment method in Kill Bill has a unique uuid associated to it. Use this uuid to change the default payment method on the account (in this example, the payment method id a91161b0-d159-11e3-9c1a-0800200c9a66 becomes the default one):

The withPluginInfo query parameter tells Kill Bill to fetch plugin specific properties. These properties are custom key/value pairs the plugin knows about the payment method, that are specific to that payment method.

The payment method will be marked as inactive in Kill Bill. The actual deletion of the information is plugin specific (delete the information in the gateway, etc.).

Note that by default you cannot delete the default payment method on an account (because it is assumed to be used for recurring payments). If you really want to delete it though, you can pass the query parameter deleteDefaultPmWithAutoPayOff=true to the previous call. This will delete it and set the account in AUTO_PAY_OFF (invoices won’t be paid automatically anymore).

Payment APIs

Direct Payments APIs

A payment object is associated with a set of transactions (authorization, multiple captures, etc.). You can retrieve that object via:

The calls below describe how to create payments. For each call, you can specify in the body a transactionExternalKey string to tag your payments (it represents a unique identifier in an external system).

Authorization

To create an authorization on the default payment method of the account:

The plugin will deserialize either the request body and/or the url query parameters to process the notification and return a properly formatted HTTP response object for the gateway (some gateways require specific response codes or headers to consider the notification processed and prevent retries).

Because this endpoint needs to be on a public IP (to be accessible from the gateway), we recommend using the Kill Bill Notifications Proxy to avoid exposing the entire Kill Bill server.