DEV Community

Cover image for API-first Invoicing – A Guide to Simplifying Financial Document Generation
Andrey Korchak for Monite

Posted on

API-first Invoicing – A Guide to Simplifying Financial Document Generation

Issuing invoices and other financial docs is something that rarely bothers tech teams. It’s something we all have to do, but there is no much value for customers in having access to financial documents.

Building yet another invoicing feature in your application looks like a simple and extremely boring thing to work on. Most engineers put together a bunch of HTML-based templates, and a PDF rendering library and start spitting out a bunch of boring financial documents.

Sometimes invoicing solutions come together as a part of payment services. Companies like Stripe supply their customers with pretty basic invoice generators integrated right into the payment gateway. That is a much simpler way to go, but it has disadvantages in terms of compliance in disadvantages.

These two solutions are equally boring and wrong at the same time.

First of all, invoices generated by your software system have to be compliant. Different countries and states have completely different understandings of what 'compliant' means. Some countries require valid business tax IDs to be present on every invoice. Some countries don't.
Some countries require to put quite sophisticated VAT rates on invoices. Some countries don't. Some countries have a specific look at financial documents, with strict requirements for the position of elements, IDs, and codes on documents. Some countries don't.

So most likely, if you just insert an HTML template into PDF render, you end up with an incompliant invoice in hand. What does 'incompliant' usually mean? it means 'loss of money'. Incorrect invoices may be not accepted by your/your customer's tax authorities, which leads to extra time and work spent on clarifying and re-doing financial paperwork. Missing compliant VAT information may lead to wrong VAT calculations which leads to extra taxes that must be paid to the government.

The second problem is that often invoice-related business scenarios are more complex than we used to think. There is a whole universe of invoice-related documents that often are involved in the process of receiving money or making payments from your account. These are purchase orders, credit notes, and full or partial cancellation notes. And all of these docs often have to be exported into 3rd party accounting software.

Both things, compliance, and different business cases, are boring, costly, and annoying to deal with. Especially if finances are not your main product and engineering expertise. That often happens in marketplaces, CRMs, and small-medium business management tools. In these software products, the main goal of the product team is to deliver features and customers and not to deal with annoying financial documents. But if you are not making invoices and other documents right, that will create frustration for your customers who have to deal with incompliant documents with missing VAT IDs (or God knows what else tax authorities wish to see on these PDF files).

Getting started

In order to avoid the situation of re-writing the same financial features using different programming languages, we designed an API that provides all necessary functionality and designed to provide solid foundations for your apps.

In short, Monite is like AWS for fintech, but instead of low-level services like servers and databases, Monite supplies users with high-level building blocks such as invoicing, payments, accounting, and many others. All building blocks can be connected to each other in all possible ways and they also can talk to each other. This leads us to API-level infrastructure which is able to provide a solid foundation for all your fintech ideas.

The Monite API platform uses a few different layers to secure access to any stored data within the platform:

Image description

  • Partner. A company that implements Monite in its app or platform. The development teams of Partners connect to the Monite API with admin-level access tokens. The admin tokens in this mandatory layer enable Partners to create and configure entities and access all resources of all entities they develop software for.
  • Entity. A customer of a Partner – an entity – is either an organization or an individual. Each Partner develops for one or more entities. With the ID of an entity, it is possible to obtain root access to all resources related to this specific entity only.
  • Entity user. The employees who work for an entity. This optional entity user access layer is for Partners who want to use Monite security for rapid development rather than build their own custom access control logic. Using the Monite API, Partners create customizable entity-level roles and permissions. Monite automatically monitors access policies for each API call.

For example, Maria is an accountant at Beispiel GmbH and Beispiel GmbH uses the online banking of  Big Money Bank. Big Money Bank is a partner, Beispiel GmbH is an entity and Maria is an entity user.

To start building your invoicing solution, the first thing you as an API partner need to do is to register your partner account on the Monite Partner Portal.

Then you have to create your project and get credentials for it.

The API ID and secret need to be exchanged for an access token which is then used to authenticate the API calls.

curl -X POST 'https://api.sandbox.monite.com/v1/auth/token' \
     -H 'Content-Type: application/json' \
     -d '{
        "grant_type": "client_credentials",
        "client_id": "28c10852-7e78-43cf-abfb-efeed1834963",
        "client_secret": "615b3cfa-646b-41d9-b768-521f09315ac5"
     }'
Enter fullscreen mode Exit fullscreen mode

Mapping your users to Monite

Usually, Monite is used when a tech team wants to add a fintech feature to an existing software product. It means users, roles, and permissions are already implemented inside of that product. But in order to make invoicing work, we somehow need to connect that existing access management function of the parental product with Monite API.

And in order to do that, we need to map existing users of our customers into Monite API and Monite will take care of all aspects of access control of invoicing feature.

First, we create an entity representing your customer. Let’s assume your software provides business services to Bob Jones who lives in Berlin. Via following API call we connect Bob Jones with Monite.

curl -X POST 'https://api.sandbox.monite.com/v1/entities' \
  -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
  -d '{
    "type" : "individual",
    "email": "bob@example.com",
    "address" : {
        "country" : "DE",
        "city" : "Berlin",
        "state": "BE",
        "postal_code" : "10115",
        "line1" : "Flughafenstrasse 52"
    },
    "individual" : {
        "first_name" : "Bob",
        "last_name" : "Jones",
        "tax_id": "1234567890"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Often multiple people operate business and they all have different permissions when we are talking about access to financial information. In order to separate different groups of people, you can create different roles with different permissions. For example, sales folks can only issue invoices, while CEO can do pretty much everything.

curl -X POST 'https://api.sandbox.monite.com/v1/roles' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
      "name": "View payables",
      "permissions": {
        "objects": [
          {
            "object_type": "comment",
            "actions": [
              {
                "action_name": "read",
                "permission": "allowed"
              }
            ]
          },
          {
            "object_type": "payable",
            "actions": [
              {
                "action_name": "read",
                "permission": "allowed"
              }
            ]
          }
        ] 
      }
    }'
Enter fullscreen mode Exit fullscreen mode

And then we put all things together and create a record for a person who works for Bob Jones:

curl -X POST 'https://api.sandbox.monite.com/v1/entity_users' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "login": "Gardner.Waelchi",
       "first_name": "Gardner",
       "last_name": "Waelchi",
       "role_id": "946141f3-ca01-44dc-b1a6-1024aa71f978",
       "email": "g.waelchi@example.com",
       "phone": "+15551234567"
     }'
Enter fullscreen mode Exit fullscreen mode

To make API calls on behalf of an entity user, you need to use an access token of that user. To get this token, call POST /auth/token with the following request body:

curl -X POST 'https://api.sandbox.monite.com/v1/auth/token' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'Content-Type: application/json' \
     -d '{
       "grant_type": "entity_user",
       "client_id": "2e0c68d6-00b7-447d-b26c-415bbcbfc026",
       "client_secret": "cf0de0bd-a59e-473f-a3dd-db5924bd8622",
       "entity_user_id": "0c76febf-aabb-451a-aabb-ea3b47689dc1"
     }'
Enter fullscreen mode Exit fullscreen mode

Invoices and account receivables

All different invoice-related documents (such as cancellation notes and purchase orders) are part of a bigger concept which is called 'account receivables'. Monite API covers lots of different business cases related to AR and everything is available via API calls.

In order to issue your first compliant invoice via API, you have to do some preparatory work.

  1. First, you have to dig into VAT rates. Monite manages VATs for you, but anyway you have to get connected to VAT rates API.
  2. Then you have to map your user’s counterparts to our system. In order to become exportable, every financial document has to refer to a specific counterpart which also will be exported into accounting solutions along with financial data.
  3. An invoice always contains information about line items such as goods and services, Every line item has to connect the valid title of service/good, price, VAT rate, and measurement units. Monite stores this information inside of API in order to make it reusable.
  4. Every compliant invoice also has to contain payment terms information. Payment terms define the amount of time one has to pay an invoice (for example, 30 days from the invoice issue date). The terms can optionally include discounts for early payments to motivate the customers to pay sooner than the due date. Without payment terms, the invoice may be considered as incompliant!

And after all their preparatory steps you can go forward and start issuing invoices.

VAT classes

Monite maintains a database of VAT rates. API users can query the available rates via the API.

Currently, Monite API provides VAT rates for the following countries:

  • 🇦🇴 Angola
  • 🇧🇪 Belgium
  • 🇧🇼 Botswana
  • 🇪🇪 Estonia
  • 🇸🇿 Eswatini
  • 🇫🇷 France
  • 🇩🇪 Germany
  • 🇮🇪 Ireland
  • 🇱🇸 Lesotho
  • 🇱🇷 Liberia
  • 🇲🇿 Mozambique
  • 🇳🇦 Namibia
  • 🇳🇱 Netherlands
  • 🇿🇦 South Africa
  • 🇪🇸 Spain
  • 🇦🇪 United Arab Emirates (UAE)
  • 🇬🇧 United Kingdom (UK)
  • 🇿🇼 Zimbabwe

We are constantly adding new countries, and please let us know if you don’t see VAT rates for some countries you want to support right now. Maintaining a valid database of actual VAT rates is a significant effort and that’s why we are doing this for you.

You can get all available VAT rates using API call:

curl -X GET 'https://api.sandbox.monite.com/v1/vat_rates?counterpart_id=3a9c5...48df' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN'
Enter fullscreen mode Exit fullscreen mode

Create and manage products

In order to make invoices right, your users need to specify products/services and measurement units for them.

curl -X POST 'https://api.sandbox.monite.com/v1/measure_units' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "name": "kg",
       "description": "Kilogram"
     }'
Enter fullscreen mode Exit fullscreen mode
curl -X POST 'https://api.sandbox.monite.com/v1/products' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "name": "Ice cream",
       "type": "product",
       "description": "A delicious vanilla ice cream",
       "price": {
         "currency": "EUR",
         "value": 1500
       },
       "measure_unit_id": "12188fc1-493d-48a7-aea8-382240dd7ce7",
       "smallest_amount": 1
     }'
Enter fullscreen mode Exit fullscreen mode

Counterparts

Counterparts represent the suppliers and clients of an entity. They can be organizations or individuals. A counterpart must be created before you can create invoices, quotes, and other documents. That’s because in order to become exportable into accounting software, every financial document needs to be linked with a specific counterpart in the system.

curl -X POST 'https://api.sandbox.monite.com/v1/counterparts' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
      "type": "organization",
      "organization": {
        "legal_name": "Acme Inc.",
        "is_vendor": false,
        "is_customer": true,
        "phone": "+4930774619876",
        "email": "acme@example.com",
        "registered_address": {
          "country": "DE",
          "city": "Berlin",
          "postal_code": "10119",
          "state": "BE",
          "line1": "Flughafenstrasse 52",
          "line2": "Additional address"
        }
      }
    }'
Enter fullscreen mode Exit fullscreen mode

Payment terms

Payment terms define the amount of time one has to pay an invoice (for example, 30 days from the invoice issue date). The terms can optionally include discounts for early payments to motivate the customers to pay sooner than the due date.

curl -X POST 'https://api.sandbox.monite.com/v1/payment_terms' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "name": "Net 30",
       "term_final": {
         "number_of_days": 30
       }
     }'
Enter fullscreen mode Exit fullscreen mode

Issuing an actual invoice

And after all this preparatory work is done, you can finally issue an invoice on behalf of your user:

curl -X POST 'https://api.sandbox.monite.com/v1/receivables' \
     -H 'X-Monite-Version: 2023-04-12' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "type": "invoice",
       "currency": "EUR",
       "counterpart_id": "0414f84c-b039-4203-b09b-e42b49245435",
       "line_items": [
         {
           "quantity": 1,
           "product_id": "8755c86a-d630-4920-b6fd-fd2917d87dfb",
           "vat_rate_id": "479155c3-0995-4689-a3cf-7482ea5132a9"
         }
       ],
       "payment_terms_id": "e2cbbb5f-15e6-4b22-a942-8f51b7a81118",
       "vat_exempt": false,
       "entity_vat_id_id": "cb6c1c38-fdae-48f8-8e51-2d50d116b882",
       "entity_bank_account_id": "3f548c1b-8f18-4021-bdd1-5624cca65c3e"
     }'
Enter fullscreen mode Exit fullscreen mode

What next?

Now you have a PDF document with all relevant financial data. But it’s just the beginning of the story. Invoices need to be delivered to recipients, then payments have to be accepted and matched against financial records. In some situations, people have to deal with recurring invoices and partially paid invoices, and all these cases need to be covered in invoicing products, otherwise, your invoicing solution will be half (or even quarter) backed. We covered these topics in our tech documentation.

The entire flow of API calls may seem a bit tricky for you. But there are ways to hide this complexity from your users. For example, VAT rates may be settled only once via a separate API call done in the background. Services and measurements can be also settled up only once if you are working, for example, on Upwork-like freelance platform, where people often produce invoices based on hours they spent working on projects.

How API works under the hood

All invoicing business flows are pretty much the same in different countries. Yes, there are differences in VAT rates, rules, and numbers, but we are talking, pretty much, about the same set of documents with the same set of properties.

We identified regional aspects of invoicing and made them configurable via configuration options coming from our internal microservices and JSON configuration files. Compliance officers and keeping these configs up to date so end users always receive complaint invoices.

Top comments (0)