This is the reference guide to get started with Kill Bill Payments Platform. Make sure to also check our main documentation here.

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.

Kill Bill Payments Platform in 5 minutes

Download the latest jetty-console.war from Maven Central (download the jetty-console.war artifact).

To start Kill Bill, either double click on the war file, or run the following in a terminal (recommended to check logs):

java -jar killbill-*-jetty-console.war

This will start Kill Bill with an embedded H2 database (data is persisted in a local killbill.h2.db file, so changes are preserved across restarts).

After the system has started, you can experiment by following the simple scenario below. Note that each call creating an object in the system returns its URI, and so the curls below are using the UUID that was returned at the time the demo was created. You would need to replace the UUID with the one returned in each call if you were to follow that demo.

If you get an error like the following at startup:

16:12:23,432 |-ERROR in [email protected] - Failed to get local hostname java.net.UnknownHostException: HOSTNAME: HOSTNAME: nodename nor servname provided, or not known
	at java.net.UnknownHostException: HOSTNAME: HOSTNAME: nodename nor servname provided, or not known

you may have an invalid hostname set. To work around it, add the following line in /etc/hosts:

127.0.0.1 HOSTNAME localhost

and restart Kill Bill.

Create your own tenant

The default behavior of Kill Bill is to run with multi-tenancy enabled. In that mode, one needs to first create a tenant and specify the credentials that will be required subsequently on each call. Each call requires a default username and password that is used in the system for role base access control (RBAC). By default we are using the username 'admin' and its default password 'password'. The first operation is to create the tenant specifying the api key and secret that will need to be provided in each subsequent call:

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"

At this point, test your setup by making sure you can retrieve the default tag definitions:

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/tagDefinitions"

Create an account

The next step will be 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]","currency":"USD"}' \
     "http://127.0.0.1:8080/1.0/kb/accounts"

Now, let’s attach a payment method to that account. Since that demo does not have any real payment plugin attached to it, we will choose the default external payment method plugin that comes configured with the system (used to process checks for example). That default payment plugin does not require any payment method details such as Credit Card info, and so the pluginInfo parameter is an empty map:

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"

{"uri":"http://127.0.0.1:8080/1.0/kb/paymentMethods/eef35072-f70e-43da-a614-3215dbc1e28a"}

Note: the payment plugin associated with this payment method will mock all calls, so all payment calls will succeed.

Create an authorization

Let’s try to authorize the payment method:

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

This will return a direct payment object. We will assume its uuid is 078a4500-d15e-11e3-9c1a-0800200c9a66 in the examples below.

Capture this authorization

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 '{"amount":"5","currency":"USD","transactionExternalKey":"INV-001-CAPTURE"}' \
     "http://127.0.0.1:8080/1.0/kb/payments/078a4500-d15e-11e3-9c1a-0800200c9a66"

Alternative with one call (also referred to as payment combo call)

In order to create the account, add the payment method and then proceed with the payment (auth, purchase, …​), we added a 'combo' payment call that will create the various states (acccount, payment method) if they don’t already exist. The call is provided as a convenience to avoid making multiple calls. It does not offer transactional properties, for instance if creating the account works but somehow adding the payment method fails, the call would fail and yet the account would end up being created. However, the call is idempotent, so retrying the call for the same account would resume the steps and thefeore not re-create the account which already exists.

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 '{
     "account": {
         "name":"My Name",
         "currency":"USD"
     },
     "paymentMethod": {
         "pluginName":"__EXTERNAL_PAYMENT__",
	     "pluginInfo":{}
	 },
	 "transaction": {
	     "transactionType":"AUTHORIZE",
	     "amount":12.5,
	     "currency":"USD"
	 }
}' \
"http://127.0.0.1:8080/1.0/kb/payments/combo"

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.

pub?w=960&h=480

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:

payment states

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:

plugin result payment transaction status payment state http response description

PROCESSED

SUCCESS

{AUTH,CAPTURE,..}_SUCCESS

201 - Created

The payment transaction went through and was successful

PENDING

PENDING

{AUTH,CAPTURE,..}_PENDING

201 - Created

Successful asynchronous operation (e.g. ACH transfer) or multi-step call (e.g. 3D-Secure authorization)

ERROR

PAYMENT_FAILURE

{AUTH,CAPTURE,..}_FAILED

402 - Payment Required

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.

In the flow diagrams below, we consider the following actors:

  • Browser: user sitting behind a browser and initiating the payment flow

  • 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.

Hosted Payment Page with redirect
Figure 1. Payment created during the redirect
Hosted Payment Page with redirect and pending payment
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.

Hosted Payment Page with polling
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.

Hosted Payment Page with notification
Figure 4. Payment created when receiving a notification from the provider
Hosted Payment Page with notification and pending payment
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.

Hosted Payment Page 3D-Secure variation
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.

Gateway integration
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:

{ "city" => "San Francisco", "billing_address" => "address[postcode]=94114" }

One would have to add the following query parameters (note that this needs to be URL encoded):

pluginProperty=San%3DFrancisco&pluginProperty=billing_address%3Daddress%5Bpostcode%5D%3D94114

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:

       "pluginInfo": {
         "properties": [{
           "key": "pluginSpecificKey",
           "value": "9876543210"
         }]

Payment Method APIs

The first step when registering payment methods is to create an account in Kill Bill. This needs to be done once:

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

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.

To add a payment method, POST the following information:

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":"__EXTERNAL_PAYMENT__","pluginInfo":{}}' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?isDefault=true"

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.

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": "20G53990M6953444J"
         }]
       }
     }' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?isDefault=true"

Check our PayPal demo for an implementation example.

The Litle&Co. plugin on the other hand expects some fields like the paypageRegistrationId (using Litle’s tokenization service):

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-litle",
       "pluginInfo": {
         "properties": [
           {
             "key": "paypageRegistrationId",
             "value": "t3GER3BP3JHLASZe"
           },
           {
             "key": "ccFirstName",
             "value": "John"
           },
           {
             "key": "ccLastName",
             "value": "Doe"
           },
           {
             "key": "ccType",
             "value": "VISA"
           },
           {
             "key": "ccExpMonth",
             "value": 12
           },
           {
             "key": "ccExpYear",
             "value": 2015
           },
           {
             "key": "ccLast4",
             "value": 1234
           },
           {
             "key": "address1",
             "value": "5, oakriu road"
           },
           {
             "key": "address2",
             "value": "apt. 298"
           },
           {
             "key": "city",
             "value": "Gdio Foia"
           },
           {
             "key": "state",
             "value": "FL"
           },
           {
             "key": "zip",
             "value": "49302"
           },
           {
             "key": "country",
             "value": "IFP"
           }
         ]
       }
     }' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods?isDefault=true"

Check our Litle demo for an implementation example.

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):

curl -v \
     -X PUT \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     -H 'X-Killbill-CreatedBy: creator' \
     "http://127.0.0.1:8080/1.0/kb/accounts/268983f2-5443-47e4-a967-b8962fc699c5/paymentMethods/a91161b0-d159-11e3-9c1a-0800200c9a66/setDefault"

To get information on a payment method, use the following endpoint:

curl -v \
     -u admin:password \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     "http://127.0.0.1:8080/1.0/kb/paymentMethods/a91161b0-d159-11e3-9c1a-0800200c9a66?withPluginInfo=true"

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.

To delete a payment method:

curl -v \
     -X DELETE \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     -H 'X-Killbill-CreatedBy: creator' \
     "http://127.0.0.1:8080/1.0/kb/paymentMethods/a91161b0-d159-11e3-9c1a-0800200c9a66"

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:

curl -v \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-ApiKey:bob' \
     -H 'X-Killbill-ApiSecret:lazar' \
     "http://127.0.0.1:8080/1.0/kb/payments/078a4500-d15e-11e3-9c1a-0800200c9a66"

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:

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

This will return a direct payment object. We will assume its uuid is 078a4500-d15e-11e3-9c1a-0800200c9a66 in the examples below.

Notes:

  • For multi-steps authorization (e.g. 3DS), you can specify a paymentId field in the body for subsequent calls

  • You can specify another payment method (other than the default one) via the paymentMethodId query parameter

Capture

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 '{"amount":"5","currency":"USD","transactionExternalKey":"INV-001-CAPTURE"}' \
     "http://127.0.0.1:8080/1.0/kb/payments/078a4500-d15e-11e3-9c1a-0800200c9a66"

Notes:

  • You can call this endpoint multiple times for partial captures (all of these captures will share the same direct payment id)

Purchase

This call is similar to the authorization one:

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

Notes:

  • You can specify another payment method (other than the default one) via the paymentMethodId query parameter

Void

curl -v \
     -X DELETE \
     -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 '{"transactionExternalKey":"INV-001-VOID"}' \
     "http://127.0.0.1:8080/1.0/kb/payments/078a4500-d15e-11e3-9c1a-0800200c9a66"

Refund

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 '{"amount":"5","currency":"USD","transactionExternalKey":"INV-001-REFUND"}' \
     "http://127.0.0.1:8080/1.0/kb/payments/078a4500-d15e-11e3-9c1a-0800200c9a66/refunds"

Credit

This call is similar to the authorization one:

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

Notes:

  • You can specify another payment method (other than the default one) via the paymentMethodId query parameter

Hosted pages helpers

Build form descriptor

The buildFormDescriptor API is used to prepare a Hosted Payment Page (HPP) payment. In the body of the request, you need to pass custom fields that are plugin specific.

For example, given an order of $10, here is how you can get the redirect URL using the Adyen plugin:

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 '{
       "formFields": [
         {
           "key": "country",
           "value": "DE"
         },
         {
           "key": "paymentProviderType",
           "value": "CREDITCARD"
         },
         {
           "key": "serverUrl",
           "value": "http://killbill.io"
         },
         {
           "key": "resultUrl",
           "value": "?q=test+adyen+redirect+success"
         },
         {
           "key": "amount",
           "value": 10
         },
         {
           "key": "currency",
           "value": "USD"
         }
       ]
     }' \
     "http://127.0.0.1:8080/1.0/kb/paymentGateways/hosted/form/268983f2-5443-47e4-a967-b8962fc699c5"

Notes:

  • Replace 268983f2-5443-47e4-a967-b8962fc699c5 with the account id

  • You can specify another payment method (other than the default one) via the paymentMethodId query parameter

Process gateway notifications

Gateway notifications (Adyen notifications, Recurly push notifications, PayPal or BitPay IPN, etc.) can be processed through the processNotification API.

For example, here is the payload that Adyen would send:

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 '<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Body>
    <ns1:sendNotification xmlns:ns1="http://notification.services.adyen.com">
      <ns1:notification>
        <live xmlns="http://notification.services.adyen.com">true</live>
        <notificationItems xmlns="http://notification.services.adyen.com">
          <NotificationRequestItem>
            <additionalData xsi:nil="true"/>
            <amount>
              <currency xmlns="http://common.services.adyen.com">EUR</currency>
              <value xmlns="http://common.services.adyen.com">2995</value>
            </amount>
            <eventCode>AUTHORISATION</eventCode>
            <eventDate>2013-04-15T06:59:22.278+02:00</eventDate>
            <merchantAccountCode>TestMerchant</merchantAccountCode>
            <merchantReference>325147059</merchantReference>
            <operations>
              <string>CANCEL</string>
              <string>CAPTURE</string>
              <string>REFUND</string>
            </operations>
            <originalReference xsi:nil="true"/>
            <paymentMethod>visa</paymentMethod>
            <pspReference>4823660019473428</pspReference>
            <reason>111647:7629:5/2014</reason>
            <success>true</success>
          </NotificationRequestItem>
        </notificationItems>
      </ns1:notification>
    </ns1:sendNotification>
  </soap:Body>
</soap:Envelope>' \
    "http://127.0.0.1:8080/1.0/kb/paymentGateways/notification/killbill-adyen"

Make sure to replace killbill-adyen with your plugin name.

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.