NAV
Shell GraphQL Response

Introduction

Welcome to the Clearfacts Developer Documentation.
We offer a public API available to all our users, partners, and app developers.

In this documentation you'll find information on how to authenticate and connect to our API, as well as in depth information on the functionality it exposes.

Technology

Getting help

If you have any questions regarding our API please contact our developer support via email at dev-support at clearfacts dot be.

Using this documentation

Wherever possible, there will be concrete examples provided in the area to the right. For navigation, you can quickly move around using the menu on the left.

GraphQL

What is GraphQL ?

GraphQL is a data query language developed by Facebook in 2012.

It was published in 2015 and has since been adopted by major tech products like GitHub, YouTube or Pinterest to build the most recent versions of their APIs.

GraphQL provides an alternative to REST and allows clients to define the structure of the data required, and exactly the same structure of the data is returned from the server. It is a strongly typed runtime which allows clients to dictate what data is needed. This avoids both the problems of over-fetching as well as under-fetching of data.

More information on GraphQL can be found here (amongst plenty of others):

The GraphQL Endpoint

Where REST has several endpoints, graphQL has just one:

https://api.clearfacts.be/graphql

The Schema

We generate documentation from our GraphQL schema. All calls are validated and executed against the schema. Use these docs to find out what data you can query, and which operations you can execute.

View our GraphQL Schema.

Examples

Throughout this documentation, we'll provide examples where possible.

However, since every GraphQL or HTTP Client library has its own syntax of actually setting the query and/or variables, we only provide the plain GraphQL query or mutation itself. Not the function calls to set them in your library of choice.

Regardless, the end result should be:

Operations

Authentication

To use our API you need to authenticate using a valid API token that has the right scopes.

When using such a token you will be able to act on behalf of the Clearfacts user for which the token was created.

A token can be acquired in two ways, and we'll break them down in the following sections.

Personal Access Token

A personal access token is created once, manually, by a Clearfacts user. This means that the user needs to log in to the Clearfacts web platform and create the token through the user interface.

This is typically used for offline or desktop applications. For (online) applications used by multiple users, we recommend using OpenID Connect instead.

As a developer, either:

Personal access tokens are similar to OAuth2 bearer tokens, but they do not expire.

This means it's an easy way to get a token for talking to the API using command line tools, e.g. while exploring the API's capabilities.

Personal access tokens are always exactly 80 ASCII characters (or bytes) long.

Creating an Personal Access Token

To create a personal access token, you need to follow these steps:

  1. Log in to the Clearfacts web platform.
  2. In the top right corner, click on your profile and select "Integrations".
  3. Click on the button "Create new token".
  4. Give your token a descriptive name.
  5. Select the scopes you'd like to grant your token.
  6. Click the "Save" button
  7. The newly created token is displayed in a message box. Make sure to copy it, as it is only displayed once.

Testing your token

# Replace `<token>` with your actual personal access token.
curl -H "Authorization: Bearer <token>" \
  -X GET \
  https://login.clearfacts.be/oauth2-server/userinfo
{
  "sub":"user@domain.com",
  "username":"user@domain.com",
  "email":"user@domain.com"
}

You can use a simple curl request to test your token, and information about the user for whom the token was created.

OpenID Connect

If you're a developer and want to enable the users of your application to generate access tokens, effectively granting your application access to Clearfacts on their behalf, then implementing OpenID Connect (OIDC) is the way to go.

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the user based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the user in an interoperable and REST-like manner.

Building a secure OpenID Connect client is difficult, so you should use an existing and proven implementation in the language of your choice. Click here for a list of client libraries.

If you're interested in learning more, check out the following link: An intro on OpenID Connect.

Application Registration

In order to use OpenID Connect, your application needs to be registered with Clearfacts. This can now be done through the Clearfacts web platform.

As a developer, either:

To create an application, you need to follow these steps:

  1. Log in to the Clearfacts web platform.
  2. In the top right corner, click on your profile and select "Integrations".
  3. Click on the button "Create new application".
  4. Give your application a name.
  5. Fill in the Redirect URI that the user should land on after authorizing the application.
  6. Click the "Save" button
  7. The Client ID and Secret for the newly created application are displayed in a message box. Make sure to copy them, as they are only displayed once.

Auto Discovery

curl -X GET \
  https://login.clearfacts.be/.well-known/openid-configuration
{
    "issuer": "https://login.clearfacts.be",
    "authorization_endpoint": "https://login.clearfacts.be/oauth2-server/authorize",
    "token_endpoint": "https://login.clearfacts.be/oauth2-server/token",
    "userinfo_endpoint": "https://login.clearfacts.be/oauth2-server/userinfo",
    "jwks_uri": "https://login.clearfacts.be/oauth2-server/jwks.json",
    "response_types_supported": ["code", "token"],
    "subject_types_supported": ["public"],
    "id_token_signing_alg_values_supported": ["RS256"],
    "scopes_supported": ["openid", "profile", "email"]
}

OIDC has a way to configure clients automatically through a Discovery Document URL. The URL for this is defined by the OIDC spec and can be inspected manually if you'd like to see which features are supported in our implementation.

https://login.clearfacts.be/.well-known/openid-configuration

Authorization Code flow

OpenID connect (or OAuth2) supports several flows to obtain an access token.

Currently we only support the "Authorization Code Flow". This is the most commonly used and most secure flow, but it cannot be used by client-side only apps like javascript apps without a back-end. To learn more about how this works, click here.

Access Token

The token that you'll receive using OIDC is not a random byte string, but a signed JWT token that can be decoded (see: jwt.io).
The JWT token contains the basic claims (sub, username, email) as well as an access token.
This is an access token, 80 character long, like you would get when manually creating a personal access token.

Both the JWT token and the access token can be used in the Authorization header.
Authorization: Bearer <token> This means you can store either one depending on your use case.

Multiple Tokens

You can create multiple tokens for a user and application combination.

This is useful if your applications supports multiple workflows. For example:

Using multiple tokens, your application can perform the authorization flow for each use case, requesting only the scopes needed.

The number of active tokens is limited to 10. If your application requests more than that, the least recently used tokens (with the same scopes being requested) will be revoked.

Scopes and Claims

The OAuth2 protocol is a delegated authorization mechanism, where a client application requests access to resources controlled by the user (the resource owner) and hosted by an API (the resource server). The authorization server typically issues the client application a more restricted set of credentials than those of the user.

Scopes

You can use scopes to:

This is a list of all the supported scopes in our API:

Scope Type Description
openid OpenID This is a technical scope, it should always be requested when using the OpenID Connect flow, it also allows access to a unique identification of the user (the sub claim)
email OpenID Access to a users emailaddress (via the /userinfo endpoint)
profile OpenID Access to a users name, locale
accountant API Consult the details of the accountant
statistics API Consult accountant statistics
read_administrations API Allows the client to query the list of administrations the user has access to
associate_read API Consult employees
associate_actions API Modify and create employees
journal_read API Consult the company's journals
contact_read API Consult the company's customers
upload_document API Allows the client to upload documents and invoices for the administrations the user has access to
archive_read API Consult the list of available archive categories
archive_actions API Making adjustments in archive
archive API Combination of archive_read and archive_actions

Each token, be it a personal access token or a token acquired through OpenID Connect, should have been granted one or more scopes for it to be of any use.

If you are using OpenID Connect, you are required to request the openid scope.

Claims

OpenID Connect specifies a set of standard claims. These claims are user attributes and are intended to provide the client with the user's details such as email, name, and locale.

Requesting individual claims is not supported in our OIDC implementation. Access to claims is regulated through scopes (openid, email, profile).

The /userinfo endpoint will return a json object with the claims.

Claim Type Required scope Description
username string openid The username as used in Clearfacts.
sub string openid Subject-identifier for the user in the Clearfacts. It contains the same value as the 'sub' claim.
name string profile User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the user's locale and preferences.
given_name string profile Given name(s) or first name(s) of the user.
family_name string profile Surname(s) or last name(s) of the user.
preferred_username string profile Shorthand name by which the user wishes to be referred to.
email string email The user's e-mail address. Note: in most cases the username equals the email address.
locale string profile The user's locale, represented as a BCP47 [RFC5646] language tag. This is typically an ISO 639-1 Alpha-2 [ISO639‑1] language code in lowercase and an ISO 3166-1 Alpha-2 [ISO3166‑1] country code in uppercase, separated by a dash. For example, nl-BE.

Granting and Revoking scopes

Personal Access Token
In case of a personal access token, the user can select which scopes to grant. It's possible to grant or revoke scopes later on by editing or deleting the personal access token in the application.

OpenID Connect Token
When using OpenID Connect, tokens are issued to the client application any time the client application requests a token and the users approves. This process is typically hidden from the user and this it's not possible to change the scopes for any existing token.

If a user wants to revoke rights from a client application he will need to remove the client application from within Clearfacts. At that point all tokens for this client application will be revoked at once.

Recipes

In this section we provide you with a variety of examples using GraphQL queries and mutations. That way you'll quickly be familiar with the usage and common use cases of our GraphQL schema and endpoint.

Due to the nature of GraphQL, the query or mutation you send determines the shape of the response you get back. This means that you can always request exactly the data you need, and nothing more. Our examples list a set of fields to request, but feel free to modify them to your own needs.

The exact contract for all of our queries and mutations are listed in our GraphQL Schema.

Query - Accountant

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query accountant {
  accountant {
    name,
    companyNumber,
    email,
    address {
      streetAddress,
      country {
        iso2,
        name
      }
    }
  }
}
{
  "data": {
    "accountant": {
      "name": "Acme Company",
      "companyNumber": "0123123123",
      "email": "accountant@acme.be",
      "address": {
        "streetAddress": "Street 16",
        "country": {
          "iso2": "BE",
          "name": "Belgium"
        }
      }
    }
  }
}

This queries the accountant the user is linked to.

The list of potential arguments can be found on the Query page.
The result will be a singular Accountant object.

Query - Associates

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query associates {
  associates {
    id,
    email
  }
}
{
  "data": {
    "associates": [
      {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "email": "account.manager@acme.be"
      }
    ]
  }
}

This queries the associates of the accountant the user is linked to.

The list of potential arguments can be found on the Query page.
The result will be a list of Associate objects.

Query - Associate Groups

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query groups {
  associateGroups {
    id,
    name
  }
}
{
  "data": {
    "associateGroups": [
      {
        "id": "2ff2f0a8-3753-11e8-8c32-02907d97d1d8",
        "name": "Test Group"
      }
    ]
  }
}

This queries the associate groups of the accountant the user is linked to.

The list of potential arguments can be found on the Query page.
The result will be a list of AssociateGroup objects.

Mutation - Add Associate

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
  -F 'query=<query>' \
  -F 'variables={ "associate": { "firstName": "Test", "lastName": "Associate", "email": "associate@acme.be", "type": "ADMIN", "associateGroups": [{ "id": "2ff2f0a8-3753-11e8-8c32-02907d97d1d8" }], "active": true, "language": "nl_BE", "sendActivationMail": false } }'
mutation add ($associate: AddAssociateArgument!) {
  addAssociate (associate: $associate) {
    id,
    associateGroups {
      id,
      name
    },
    plainPassword
  }
}
{
  "data": {
    "addAssociate": {
      "id": "198772ef-d095-4859-9328-dc47950853b9",
      "associateGroups": [
        {
          "id": "2ff2f0a8-3753-11e8-8c32-02907d97d1d8",
          "name": "Test Group"
        }
      ],
      "plainPassword": "generatedPassword123"
    }
  }
}

This adds a new associate to the accountant the user is linked to.

The list of potential arguments can be found on the Mutation page.
The result will be a singular Associate object.

Mutation - Edit Associate

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
  -F 'query=<query>' \
  -F 'variables={ "id": "198772ef-d095-4859-9328-dc47950853b9", "associate": { "firstName": "Updated" } }'
mutation edit ($id: ID!, $associate: EditAssociateArgument!) {
  editAssociate (id: $id, associate: $associate) {
    id,
    firstName
  }
}
{
  "data": {
    "editAssociate": {
      "id": "198772ef-d095-4859-9328-dc47950853b9",
      "firstName": "Updated"
    }
  }
}

This edits an existing associate of the accountant the user is linked to.

The list of potential arguments can be found on the Mutation page.
The result will be a singular Associate object.

Query - Administrations

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query admins {
  administrations {
    name,
    companyNumber,
    accountManager,
    emails {
      type,
      emailAddress
    }
    address {
      streetAddress,
      country {
        iso2,
        name
      }
    }
  }
}
{
  "data": {
    "administrations": [
      {
        "name": "Acme Company",
        "companyNumber": "0123123123",
        "accountManager": "account.manager@acme.be",
        "emails": [
          {
            "type": "purchase",
            "emailAddress": "aankoop-0123123123@acme.clearfacts.be"
          },
          {
            "type": "purchase",
            "emailAddress": "achat-0123123123@acme.clearfacts.be"
          }
        ],
        "address": {
          "streetAddress": "Street 16",
          "country": {
            "iso2": "BE",
            "name": "Belgium"
          }
        }
      }
    ]
  }
}

This queries all the administrations the user has access to.

The list of potential arguments can be found on the Query page.
The result will be a list of Administration objects.

Query - Administration

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query admin {
  administration (companyNumber: "0123123123") {
    name,
    companyNumber,
    accountManager,
    emails {
      type,
      emailAddress
    }
    address {
      streetAddress,
      country {
        iso2,
        name
      }
    }
  }
}
{
  "data": {
    "administration": {
      "name": "Acme Company",
      "companyNumber": "0123123123",
      "accountManager": "account.manager@acme.be",
      "emails": [
        {
          "type": "purchase",
          "emailAddress": "aankoop-0123123123@acme.clearfacts.be"
        },
        {
          "type": "purchase",
          "emailAddress": "achat-0123123123@acme.clearfacts.be"
        }
      ],
      "address": {
        "streetAddress": "Street 16",
        "country": {
          "iso2": "BE",
          "name": "Belgium"
        }
      }
    }
  }
}

This queries a specific administration the user has access to.

The list of potential arguments can be found on the Query page.
The result will be a singular Administration object.

Mutation - Upload File

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
  -F 'query=<query>' \
  -F 'variables={ "vatNumber": "0123123123", "fileName": "test_upload.pdf", "invoiceType": "PURCHASE" }' \
  -F file=@/home/user/Documents/example.pdf
mutation upload ($vatNumber: String!, $fileName: String!, $invoiceType: InvoiceTypeArgument!) {
 uploadFile (vatnumber: $vatNumber, filename: $fileName, invoicetype: $invoiceType) {
   uuid,
   amountOfPages
 }
}
{
  "data": {
    "uploadFile": {
      "uuid": "B74D7E7D-2408-4517-AA31-BB76018E844D",
      "amountOfPages": 1
    }
  }
}

This mutation uploads a file to the Inbox of a specific administration the user has access to.

The list of potential arguments can be found on the Mutation page.
The result will be a singular File object.

The way in which we send this mutation differs a bit from regular queries. Since we have to provide a file as data, we will send our information as form-data instead of a text-based content-type like application/json or application/graphql.

The file must be present as a parameter named file, while the mutation and arguments can be provided as regular text-based content in the form, respectively called query and variables.

Query - Document

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query doc {
  document (id: "B74D7E7D-2408-4517-AA31-BB76018E844D") {
    date,
    ... on InvoiceDocument {
      type,
      paymentState
    }
  }
}

{
 "data": {
    "document": {
      "date": "2025-01-01",
      "type": "PURCHASE",
      "paymentState": "UNPAID"
    }
  }
}

This queries a specific document the user has access to.
It's only possible to query documents for which the ID is known.
The only way to get a document's ID is after the initial upload.

The list of potential arguments can be found on the Query page.
The result will be a singular InvoiceDocument object, which extends from Document.

In our example we illustrate how to query these fields. The date field is part of the Document, so you can query the field like you normally would. The type and paymentState however are fields of the InvoiceDocument. To query these fields we need to use inline fragments ... on InvoiceDocument.

Query - Archive Categories

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query categories {
  archiveCategories (vatnumber: "0123123123") {
    various {
      id,
      name
    },
    permanent {
      id,
      name
    }
  }
}
{
  "data": {
    "archiveCategories": {
      "various": [
        {
          "id": "f5c3d05a-2d05-4329-ae31-3f144bfbeb41",
          "name": "Beleggingen"
        }
      ],
      "permanent": [
        {
          "id": "2fcff67d-3753-11e8-8c32-02907d97d1d8",
          "name": "Huurovereenkomst"
        }
      ]
    }
  }
}

This queries all the archive categories for a specific administration the user has access to.

The list of potential arguments can be found on the Query page.
The result will be a singular Categories object, which contains the various and permanent properties. Those contain an array of Category objects.

Mutation - Upload Archive File

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
  -F 'query=<query>' \
  -F 'variables={ "vatNumber": "0123123123", "fileName": "test_upload.pdf", "type": "VARIOUS", "category": "f5c3d05a-2d05-4329-ae31-3f144bfbeb41" }' \
  -F file=@/home/user/Documents/example.pdf
mutation upload ($vatNumber: String!, $fileName: String!, $type: VariousType!, $category: String!) {
 uploadArchiveFile (vatnumber: $vatNumber, filename: $fileName, type: $type, category: $category) {
   uuid,
   amountOfPages
 }
}
{
  "data": {
    "uploadArchiveFile": {
      "uuid": "B74D7E7D-2408-4517-AA31-BB76018E844D",
      "amountOfPages": 1
    }
  }
}

This mutation uploads a file to the Various or Permanent Archive of a specific administration the user has access to.

The list of potential arguments can be found on the Mutation page.
The result will be a singular File object.

This mutation is very similar to the Mutation - Upload File.
The category argument is an ID of a category retrieved using the Query - Archive Categories.

Query - Journals

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query journals {
  journals (companyNumber: "0123123123") {
    id,
    name,
    creditNote
  }
}
{
  "data": {
    "journals": [
      {
        "id": "CFAK",
        "name": "ClearFacts Aankopen",
        "creditNote": false
      }
    ]
  }
}

This queries all the journals of a specific administration the user has access to.

The list of potential arguments can be found on the Query page.
The result will be a list of Journal objects.

Query - Customers

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query customers {
  customers (companyNumber: "0123123123") {
    id,
    name
  }
}
{
  "data": {
    "customers": [
      {
        "id": "ACME",
        "name": "Acme Corporation"
      }
    ]
  }
}

This queries all the customers of a specific administration the user has access to.
For performance reasons, this list is paginated. A maximum of 100 customers will be returned per request If there are more customers to retrieve, you can use the offset argument to get the next page.

The list of potential arguments can be found on the Query page.
The result will be a list of BusinessPartner objects.

Query - Company Statistics

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
query statistics {
  getCompanyStatistics (type: "AIR", startPeriod: "2025-01-01", endPeriod: "2025-12-31") {
    companyNumber,
    items {
      period,
      value
    }
  }
}
{
  "data": {
    "getCompanyStatistics": [
      {
        "companyNumber": "BE0123123123",
        "items": [
          {
            "period": "01/2025",
            "value": 5
          }
        ]
      }
    ]
  }
}

This queries the company statistics of a specific administration the user has access to.
The main argument is the type of statistics you want to retrieve:

The list of potential arguments can be found on the Query page.
The result will be a list of CompanyStatistic objects. One entry per administration, with a list of items, one per "month/year" period.

Mutation - Update App Info

curl -H "Authorization: Bearer <token>" \
  -X POST \
  https://api.clearfacts.be/graphql
  -F 'query=<query>' \
  -F 'variables={ "vatnumber": "0123123123", "imageUrl": "XXX", "emailAddress": "test@clearfacts.be", "badgeText": "NEW", "badgeTextColor": "#d5a855", "badgeColor": "red", "iconType": "trophy", "iconColor":"yellow" }'
mutation update ($vatnumber: String!, $imageUrl: String, $emailAddress: String, $badgeText: String, $badgeTextColor: String, $badgeColor: String, $iconType: String, $iconColor: String) {
  updateAppInfo (vatnumber: $vatnumber, imageUrl: $imageUrl, emailaddress: $emailAddress, badge: { text: $badgeText, textColor: $badgeTextColor, color: $badgeColor }, icon: { type: $iconType, color: $iconColor }) {
    vatnumber,
    imageUrl,
    emailaddress,
    icon { type, color },
    badge { text, textColor, color }
  }
}
{
  "data": {
    "updateAppInfo": {
      "vatnumber": "0123123123",
      "imageUrl" : "XXX",
      "emailaddress": "test@clearfacts.be",
      "icon": {
        "type": "trophy",
        "color": "yellow"
      },
      "badge": {
        "text": "NEW",
        "textColor": "#d5a855",
        "color": "red"
      }
    }
  }
}

You can create or update customization for the app connected to your integration.
If you want an app connected to your integration, please contact support at clearfacts dot be.

The list of potential arguments can be found on the Mutation page.
The result will be a singular AppInfo object.