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 of PluginProperty, 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 type EXTERNAL_CHARGE, CREDIT_ADJ, TAX. These fields do not get saved on the database and will not be returned in subsequent GET 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.