Overview
InvoicePluginApi
The InvoicePluginApi exists to develop invoice plugins
. The core invoice system calls those plugins each time the system is generating a new invoice. The invoice system will first compute all the items based on the existing subscriptions or usage data associated to the account and then invoke the registered plugins to allow to add extra items on that invoice.
Plugins need to implement one api getAdditionalInvoiceItems, whose purpose is to to allow plugins to add additional items and which takes the following parameters:
-
invoice
: A copy of the current invoice being generated by the system (including all items generated by the system, and only items generated by the system) -
properties
: An empty list ofPluginProperty
, which means this field exists only for symmetry with other plugin apis, but is not used. -
context
: The call context associated to that invoice (mostly interesting for plugins to identify the tenant)
If multiple plugins have been registered (we don’t advise for that, unless there is a very good reason), the system will invoke all of them in no particular order. Each plugin will only see the original items generated by the system, but the union of all items generated by all plugins would end up on the invoice.
Plugins are restricted in the type of items they can add because some items (e.g RECURRING) need to match existing subscription or usage data associated to the account. The following types are allowed:
-
EXTERNAL_CHARGE
-
ITEM_ADJ
-
TAX
Plugin Activation
Invoice plugins are registered through the per-tenant org.killbill.invoice.plugin
property (CSV list of plugin names) and invoked in order.
Retries
Invoice generation can be aborted and retried at a later time if the plugin is unable to compute the additional items (e.g. third-party tax service unavailable). The mechanism to do so is very similar to the retry mechanism for notification plugins: the plugin simple needs to throw an InvoicePluginApiRetryException. The default retry schedule is 5m, 15m,1h,6h,15h
as defined here. However, users can also specify a custom retry schedule.
Take a look at the Notification Plugin documentation for more details.
A note about invoice item ids
When returning InvoiceItem
objects back to Kill Bill, it is recommended to set the id
value to null
.
However:
-
For new invoices or if an invoice is still in
DRAFT
mode, invoice plugins are allowed to update existing items, instead of adding new ones, by respecting the invoice item id returned by Kill Bill. This can be useful for instance to update tax amounts. -
It is worth noting that, specifying fields like
linkedInvoiceItemId
,subscriptionId
will have no effect while adding invoice items of the typeEXTERNAL_CHARGE
,CREDIT_ADJ
,TAX
. These fields do not get saved on the database and will not be returned in subsequentGET
requests. -
If the invoice plugin needs to keep track of the items it added, it can set the
id
which will be respected by the core system. Such values are expected to be globally unique.
Use Cases
Tax Plugin
One of the main use case of this api is to allow plugins to add TAX
items. Kill Bill by default knows nothing about tax, and that logic is deferred to plugins implementing this api. Example of such existing plugins are:
-
Avalara tax plugin: This is a plugin that interracts with the third party
Avalara
. -
Simple tax plugin: This is a simple tax plugin that was developed mostly as a use case for the api or to address use cases where tax calculation is simple.
Invoice Customization
There are many use cases where one would want to modify existing invoices. For instance one could implement a way to generate discounts based on certain heuristics (for a given tenant/account/subscription some discount could apply). In those scenarios, the plugin would add ITEM_ADJ
items to reflect the discount.
A reverse use case is one where a plugin needs to add extra charges that are unknown of the system (Kill Bill) and also based on some heuristics that are only known from the plugin.