Skip to main content

International Invoices (if you live in the right parts of the world)

Our newest feature, international invoices turned out to be quite tricky: which languages to offer for which countries? Then, there are different regulations for what has to appear on invoices - and, this is based not only on the country of the hotel, but also of the customer. Did you know that many Polish companies will only reimburse your travel expenses when you print that company's tax id? Neither did we.

But in the end, we managed, and here you go: with apaleo you can now generate legally okay invoices for Finland (in Finnish, English and Swedish) and Germany (in German and English). And we have a recipe for how to roll that out for the rest of the world.

Today we want to share our story: a journey from despair and overwhelming complexity to a neat little feature. Enjoy.

Playing Detectives

Our favourite source of reliable or random information, the interwebs, is pretty quiet when it comes to invoicing requirements for all the countries. The second best source, fun text books and laws always seem to written in the language of the country they are relevant for. Unfortunately, our Finnish or Japanese aren't great, and we resorted to unorthodox methods: travelling the world, collecting invoices from all over the place, asking hotel owners we know for examples, calling friends ("Hey, we haven't talked in months! How are you and can you send me a sample invoice?")

That was quite fun, and it worked, but we figured doing that for all of the world in advance would delay that feature by a few decades.

Divide and conquer

The solution to that was to focus on what we needed now: not international invoices for everything and everywhere, but only for the countries we already have customers in. Plus a methodology for how to extend that to other countries with little and predictable efforts. The feature's description changed to "With zero configuration efforts for the hotel, support invoices that will make business travellers from most countries happy, in the country's official languages plus English, for one specific country where we know at least one experienced hotelier", and the hardcore problem from the beginning could be split up into three okay-ish easy research-tasks:
  1. What data do companies require on invoices, in order to accept them for travel expenses?
  2. What are the official or important languages of country X?
  3. How does a legally okay invoice look like for country X?
The first one is independent on the country the hotel is located in and a one-time effort, the second one is really simple, and the last one is just asking the previously mentioned experienced hotelier to tell us everything he knows and send us examples.

The magic pipeline

The last piece in the puzzle was finding an implementation paradigm to make supporting new countries a less-than-one-hour task. Which wasn't exactly a no-brainer, as there are so many aspects to that:
  • using the right date, time and money formatting (country specific)
  • translating user data (language specific)
  • translating static texts (language specific)
  • displaying the legally required information (country specific)
The first and second point can be super nicely handled in dotnet core, which makes data preprocessing the first step in our pipeline. All steps after this one are completely oblivious to formatting or translating, and just render it as they get it. Extending that part to support more languages / locals is exactly no work at all - it just magically works.

Next, we process partials. Those are parts which are common for multiple countries, like the header (date, recipient) and footer (hotel address, bank details, ...), and can be shared. This requires a little additional work when a new language comes in, as we translated the static texts from point three directly in the partials. We expect to create 0 to 2 new partials, when adding a new country. Getting closer to 0, the more countries we have.

Last, the main template and the partials are assembled. Each country has one template in each supported language, making this the only point that requires real work.

And very last, we need to add a new value to the enum of supported countries.

We timed it, and it's totally doable in less than an hour. Which is not bad, for rolling out to a whole new country.

How to use it?

Now you're probably wondering how you can use it on the API, right? On the POST invoice endpoint in the Finance module, specify the language you want. And we take care of the rest.

We hope you like it, and hey, if you happen to be an expert on invoices in a specific country and want to share your knowledge... we'd love to hear from you on

❤ Your apaleo team


Popular posts from this blog

Getting Started with apaleo APIs

Have a look You can find all of apaleo's API on We use Swagger to describe it, and to generate our documentation.

Sign up The first step is to sign up for an account. After you finish signup you will be able to login to our apaleo app and start configuring your properties. Also you can use the same credentials to access our API using Swagger. Get access for app We're still new and want to get in touch with you before we grant you access. Contact us at, to get your very own client credentials that lets you play with the API in our sandbox.
Use it apaleo APIs are protected using OAuth2 - the de-facto standard for API security. Here's a short guide to get you started:

Step 1: To get access to our APIs, you need to use your client id and secret to obtain an access token. Don't have one? Contact us at

Combine your client id and secret into a string, separated by colon yourClientId:YourClientSecret and encode with Base64. This wi…

Connect your app with OAuth 2.0

What is this all about? When you connect your app to apaleo, it can read or modify data, or even trigger entire business flows of a hotel. But before gaining access to any of the resources in the REST API, it must get permission from the hotel. This guide will walk you through the authorization process (described in greater detail by the OAuth 2.0 specification). Note: apaleo's OAuth 2.0 implementation supports the standard authorization code grant type. You should implement the application flow described below to obtain an authorization code and then exchange it for a token. (The implicit grant type is not supported.) Terminology Before learning more about the details of the authorization process, make sure that you are familiar with some of the key terms that are used in this guide: Client: Any application that would like access to a hotel's data. A user (usually the hotel's owner or admin) must grant permission before the client can access any data.API: apaleo REST API. T…

Channel Integration Guide

With the channel integration you can subscribe for availability, rates and inventory (ARI), create new bookings and modify existing bookings. 
The BasicsGet your sandbox account and check out this guide to learn how you can connect to the apaleo APIs.
API Client All apaleo APIs are described as swagger documents. That lets you generate API clients directly from the swagger.json files. There is a large community, providing client generators for almost every language. For example, swagger code generator is a good project, which allows generation of API clients for Java, PHP, C#, NodeJS and more. This gets you up to speed very fast and as a bonus you can access API documentation within the auto-generated methods and models. is our – and your – playground to do first steps with the API, up to your final integration. Use it to interactively explore the API or to learn the apaleo concepts by navigating the user interface.

These are the links you need to know