This post discusses how the open-source invoicing solution Invoice Ninja can be integrated with WooCommerce. The post focuses on Invoice Ninja and explains its downsides and problems.
Reasons for integrating Invoice Ninja and WooCommerce
At Bienenplatzerl.at we try to combine modern beekeeping with technology. Keeping the cost of operation as small as possible is an important factor. Therefore, we aim to utilize open-source products that are allowed to be used commercially at no cost, and run them on our own infrastructure.
This post explains how to integrate the free invoicing solution Invoice Ninja with our existing online shop, which is implemented using WooCommerce on WordPress. Most of our business are cash sales, which means the stock count in our WooCommerce online shop has to be updated on a regular basis – til now, this was done by hand. To automate this tedious task, we utilized the subscription feature of Invoice Ninja to decrease the stock count upon the creating of an invoice.
The source code of this integration project can be found on GitHub.
Integration scenario
Invoice Ninja provides so-called subscriptions which are basically webhooks that can be registered to call a specific URI when a certain event occurs. For our use case, we want to propagate the stock count adjustment when a new invoice is created (and also reverse this adjustment in case we delete the invoice).
Fig. 1: Overview of registered subscriptions in Invoice Ninja
To accomplish this, we use Azure Functions because this allows us to quickly implement a integration mechanism that doesn’t require much maintenance. For our use case Azure Functions don’t incur any costs since they only run several times a day. Our Azure Function provides an HTTP trigger that is called by the Invoice Ninja subscription, then it determines how many items are sold by parsing the invoice data, and finally, it sends the stock adjustments to the REST API of our WooCommerce shop. Of course we could implement the WooCommerce API ourselves but there is also a NuGet package available that wraps the API.
Since we don’t want any unauthorized clients to call our Azure Function, we utilize its out-of-the-box authorization. This requires the calling Invoice Ninja webhook to provide an API key, which can be found in the Azure portal. This key can either be provided via the x-functions-key
HTTP header, or by appending the query string ?code=MYKEY
to the webhook URL. Unfortunately, Invoie Ninja doesn’t support passing an HTTP header; therefore, there is no other option the using the latter option. Keep in mind that this has the following implications:
- The URL with the code is visible to all Invoice Ninja admins. Since the permission management for administrators is only binary (either full, or no permissions), this might be a problem.
- The URL including the code might appear in application or server logs.
Learnings
Here comes the difficult part: Invoice Ninja isn’t making it easy to implement the integration. First, there is no available schema definition for the data sent via the webhook. Moreover, you have to be careful if you want to use their swagger documentation: from my experience, this does not match with the actual REST API, and versioning isn’t done correctly either.
Unstable schema
To get a feeling for how the webhook API looks like, you can have a glance at an recorded HTTP payload in the GitHub repository. Since there is no documented schema, I wouldn’t assume the schema to be stable. Generating a statically typed data transfer object from the payload might lead to breaking changes. Therefore, it is advisable to follow the Tolerant Reader pattern and parse only the elements of the payload which must be processed.
No delta of changes to an invoice
Although Invoice Ninja supports three kinds of invoice events – created, deleted, and updated –, there is no way to find out what has been changed in the event of an invoice update. In our case we want to propagate the item count from the invoice to our stock. If you register a webhook for the update event, the payload only consists the new values but no information how it has changed from the initially created invoice. This leaves us without any knowledge about how to correctly updated the stock.
Our approach to solving this problem was to query Invoice Ninja’s REST API and get the history data for an invoice. However, after some research, it turned out that the REST API does not – as opposed to the web portal – provide access to the invoice history. The only possibility would therefore be keep state regarding the invoice history in the Azure function, which seems to be far too much effort for a simple integration scenario.
I hope you enjoyed this blog post and found it useful. I’m open to your thoughts on this subject, or how to improve this post. If you know of a better open-source solution than Invoice Ninja, please leave a comment below.
Thank you!
Title photo by JJ Ying