Payment plugins integrate Kill Bill with a specific gateway (i.e. payment processor), such as Stripe or Braintree. While we already have many open-source payment plugins available on GitHub, this guide will give you pointers in case you need to develop your own.
Before reading this guide, make sure to familiarize yourself with the main payment userguide.
PaymentPluginApi overview
The PaymentPluginApi is the interface between Kill Bill and payment plugins.
Here are the actions the plugin can expose:
-
authorizePayment and capturePayment should trigger an authorization and capture respectfully (applies to credit cards only)
-
purchasePayment should trigger a generic payment (authorization with auto-capture for credit cards, ACH/SEPA, etc.)
-
voidPayment should void an authorization (credit cards only)
-
creditPayment should fund the payment method from your merchant account (similar to a refund, but no prior payment is required: this can be used to initiate an ACH for disbursement for instance)
-
refundPayment should reverse an existing (settled) charge
-
getPaymentInfo should return detailed information on the transactions for that payment (arbitrary properties can be populated in PaymentTransactionInfoPlugin#getProperties)
-
searchPayments should return payment transactions matching the specified searchKey (the implementation is up to the plugin)
-
addPaymentMethod should create the payment method in the gateway (e.g. store a token)
-
deletePaymentMethod should delete the payment method in the gateway (e.g. revoke a token)
-
getPaymentMethodDetail should return detailed information about the payment method (e.g. billing address)
-
setDefaultPaymentMethod should mark the payment method as the default one in the gateway (if the associated account in the gateway has several payment methods)
-
getPaymentMethods should list the payment methods in the gateway for that account (used by the refresh endpoint, when payment methods are added directly in the gateway, bypassing addPaymentMethod)
-
resetPaymentMethods, called at the end of a refresh call, should associate to that account the payment methods specified (this is useful if Kill Bill knows payment methods that are not yet in the gateway)
-
searchPaymentMethods should return payment methods matching the specified searchKey (the implementation is up to the plugin)
-
buildFormDescriptor should return enough metadata for the front-end to build a form or a redirect to a hosted payment page
-
processNotification should process payloads from the gateway to transition payments states
If an operation is not supported, the plugin must:
-
return an empty list when the return type is a list
-
return a transaction with status CANCELED if the return type is a PaymentTransactionInfoPlugin (see below)
-
return empty objects otherwise
PaymentPluginStatus states overview
When building PaymentTransactionInfoPlugin objects, it is very important to correctly populate the status type:
-
if the payment is successful, the plugin should return PROCESSED
-
if the payment is rejected by the gateway (insufficient funds, fails AVS check, fraud detected, etc.), the plugin should return ERROR
-
if the payment requires a completion step (3D-S verification, HPP, etc.), the plugin should return PENDING
-
if the gateway wasn’t contacted (DNS error, SSL handshake error, socket connect timeout, etc.), the plugin should return CANCELED
-
for all other cases (socket read timeout, 500 returned, etc.), the plugin should return UNDEFINED
You should try to avoid UNDEFINED as much as possible, because it is the only case where Kill Bill cannot retry payments (since the payment may or may not have happened). Kill Bill will also attempt to fix these states by polling the plugin via getPaymentInfo: if the plugin subsequently returns PROCESSED for example (maybe by querying the gateway directly), the internal payment state (as well as invoices balance, etc.) will be reflected.
Plugin Activation
When a payment operation occurs, Kil Bill will chose which payment plugin to go to based on the paymentMethodId
specified. The paymentMethodId
will map to an specific payment method, which in turns contains the name of the plugin to chose for the payment.
Payment plugins frameworks
To help with writing payment plugins, we developed Java and Ruby frameworks which ensure that the plugin will respect the previous mentioned conditions. If you are developing your own plugin, we strongly encourage you to use these libraries. The easiest is to copy an existing plugin and modify it for your gateway. The Adyen plugin (Java) and CyberSource (Ruby) plugins are good starting points.
ActiveMerchant plugin generation
ActiveMerchant is a Ruby gem supporting dozens of gateways. For convenience, we provide a tool to generate a plugin based on an ActiveMerchant connector (if your gateway is not supported by ActiveMerchant yet, it is almost always easier and faster to first write the ActiveMerchant connector and generate the plugin code, rather than implementing your plugin from scratch).
First, clone the killbill-plugin-framework-ruby repository and run:
./script/generate active_merchant gateway_name /path/to/dir
Replace gateway_name with the snake case of your ActiveMerchant gateway (e.g. yandex, stripe, paypal_express, etc.).
This will generate a tree of files ready to be plugged into Kill Bill. Most of the work will consist of filling in the blanks in api.rb (payment plugin API for ActiveMerchant gateways) and application.rb (sinatra application for ActiveMerchant integrations, i.e. Offsite Payments). For example, make sure the right constructor parameters are passed in the initialize method. Check the Stripe plugin for an example.
The generator comes with a series a basic unit and integration tests (the latter requires gateway credentials in your local YAML configuration file). To run them:
rm -f Gemfile.lock Jarfile.lock .jbundler/classpath.rb
bundle install
# Run gem install jbundler if needed
jbundle install
bundle exec rake
bundle exec rake test:remote:spec
Not all tests will work with your gateway (maybe some features are not supported): feel free to remove them. But make sure some basic calls are working noneless (e.g. purchase), as it will make debugging in Kill Bill much harder otherwise.
Building Ruby plugins
Unlike Java plugins, which are deployed as jars, Ruby plugins need a specific directory structure on the filesystem to run (containing all of the gems dependencies). Fortunately, we provide scripts to generate self-contained artifacts: all you need to do is untar (or unzip) these.
Prerequisites
Ruby 2.1+ or JRuby 1.7.20+ is recommended. If you don’t have a Ruby installation yet, use RVM:
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
\curl -sSL https://get.rvm.io | bash -s stable --ruby
After following the post-installation instructions, you should have access to the ruby
and gem
executables.
Install the following gems:
gem install bundler
gem install jbundler
Build
Please refer to the Plugin Development Documentation