How we built the API of an API-first company

DEFACTO
get-defacto
Published in
6 min readApr 27, 2022

Two months ago, our first users started integrating our REST API and now we are very happy to announce that they are live! Above all, our very first user gave a score of 4/4 to our API documentation.

We spent quite some time working on our API in the previous six months. We now think that this is a good moment to share how we did it.

So, in this blog post we will share:

  • the main guiding principles driving our decisions
  • what we prioritized and what we delayed
  • the key tools that we use
  • the main mistakes that we made

Context

At Defacto, we are a company offering invoice-based financing by API to finance working capital requirements for SMBs. So basically, companies send us invoices by API and then request loans for them. We then manage the flow of funds, and of course we analyze the ability of the borrower to repay us on time.

Antoine, who leads this topic, is a Ph.D. in web engineering. His research is about the creation of REST APIs enabling its clients to automatically evolve without requiring to update the code when breaking changes are introduced in the API.

Regarding the technologies, our API layer is implemented in python and uses Flask.

Guiding principles

We stuck to the following principles to design the API:

  • The first interaction with your API should be a delight
  • Errors will happen so they must be easy to understand
  • Things must be simple
  • We must help our users test our API in depth
  • We need as much feedback as possible to improve the API

In the rest of this article, we detail each of the above points.

Making the first interaction with your API a delight

People will always remember the first interaction that they have with our API! And the first interaction will be the API documentation. So the API documentation must look good, be clear and easy to follow.

To achieve this, we did:

Use readme.io to host our API documentation (available on https://developers.getdefacto.com).

  • Its UI makes your documentation legit for developers and non-developers (important to consider)
  • It takes the API reference from a Swagger file and offers a nice UI for it
  • And enables us to write guides for our users, that are essential to guide them

Make the first authenticated request very easy to do

  • We place authentication and first request on the second page of our documentation, right after the introduction
  • We created an endpoint displaying a welcoming message when the user is successfully authenticated (see our GET /hello)
  • If the user is not successfully authenticated, we return a message saying it explicitly.
Answer from our hello endpoint

Making errors understandable

We sincerely believe that returning clear error messages is important for two reasons:

  1. Errors will eventually happen
  2. Not understanding why errors happen is frustrating for developers and drives adoption down

The key decisions that we made are the following

Keeping the API reference in sync with the code

  • We generate the swagger file from the code
  • As soon as we deploy in production, a CI task updates the API documentation on developers.getdefacto.com
  • It prevents providing out-of-date documentation to our users, which can create a lot of “WTF?” moments

Using a single format to use for all errors (available in the documentation) in order to give consistency to our users

  • We wrote integration tests to ensure that all endpoints return this data model

Using data schemas (such as JSON schemas) to validate the request payloads and return clear and detailed errors

  • We truly believe that this is a must-have. It helps our users debug their code easily, and it also helps us do the same.
  • We use the marshmallow-dataclass library for this purpose
  • For example, if we expect an email and 8-character long password for login we would create the following schema:

Hence, if users send the following incorrect request, they will receive the following error response.

No blurry 500 errors!

  • One option to avoid 500 errors may have been to put a huge effort in the design of our exceptions. We could have created many exception classes and mapped them to detailed error messages. However, this was too much effort for us.
  • Instead, we relied on as few exception classes as possible (we have 4) and forced ourselves to write all exceptions explanation in a user-readable form.
  • One example:

On our API layer, we use a global exception handler that transforms any exception into a JSON response

We could thus include clear explanations in errors with minimal effort.

Making things simple

Resources & endpoints names should be easy to understand (#clean_code)

How we name things reflect how much we understand the concepts that we manipulate along with our ability to make them clear for our users. It’s therefore important to take time to make them as clear as possible, by taking into account how people from our industry use those words.

Follow the #standards!

  • An API takes place within an industry that has its own habits. The more we comply with those, the easier it will be for developers of that industry to integrate our API. The goal is to make them feel at home with our API, not to teach them new trendy technologies.

Document the most important usage scenarii and test them yourself

  • A swagger is only a list of functions. Making sense of this can be complicated.
  • Guiding our users within our API documentation is therefore a priority. To do so, we simply explained how to do a first loan with the Defacto API. This guide explains all the API calls to do and even offers test data generators to accelerate the process.
  • One big mistake that we did is think that everything will work fine because we had automated tests and a frontend using this API. Our first API user saw most of its calls rejected by our API. What we should have done (and so what we now do every time a new company integrates our API) is to simulate this company’s integration of our API ourselves. So we make most of the calls that our new customer will do. Doing this, we discovered and fixed many bugs before our customers could meet them.

Helping our users test our API in depth

As we offer credit by API, we wanted to make sure that the companies integrating our API will be able to react to loan refusal, delayed payments and such kinds of issues.

So, following one standard in our industry, we designed a sandbox for them to test our API.

We sincerely believe that such a test environment is necessary from day one.

In addition, we think that our users should be able to generate errors deterministically, so that they can bullet-proof their integration.

To enable this, we took inspiration from Stripe who proposes to use credit card numbers with pre-configured behaviors. So we designed a generator of IBANs (IBANs are bank account numbers), where the IBAN number encodes the behavior that our sandbox will produce (the user chooses it on generation). More information on this in our documentation.

Last but not least: getting feedback

Getting feedback is key to discovering what we did well and what we should improve.

As we are convinced that the developer experience is key, we value feedback from developers a lot.

To do so, we:

  • Create direct communication channels with the developers integrating with our API (usually on Slack)
  • Often ask for sincere feedback. We ask often because this is not easy for them to provide sincere feedback from the beginning. We must first establish a relationship of trust.
  • Send a feedback questionnaire at the end of the integration, and stay in touch with the developers

This is the End…

Thank you very much for reading this article! We hope we could share some of our learnings with you.

Feel free to reach out at tech[at]getdefacto.com for any questions, we’ll be pleased to have a chat. Check out our website: www.getdefacto.com to know more

We are hiring fun, engaged and humble engineers to build the future of Defacto.

See you in the next article 👋 (since then, don’t hesitate to share this one)

As a bonus, we provide a checklist of things to do to build your API:

  • The API reference is automatically generated from code
  • We have a nice looking and easy to understand API documentation
  • All exceptions from our code end up returning an error message that is clear for the developer
  • We made authentication easy
  • We manually tested the main scenario of use of our API
  • We use HTTP status codes properly
  • We get regular feedback from the developers integrating our API

--

--