> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maesn.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Learn how to authenticate to the maesn Unified API.

## Overview

When making requests to the maesn API you need to have the right request headers set, in order to authenticate your requests.

There are two primary authentication parts of the headers that we need to set:

* [X-API-KEY](/authentication#x-api-key-header) header
* [X-ACCOUNT-KEY](/authentication#x-account-key-header) header

These two are needed to authenticate your requests to the maesn API.

## X-API-KEY header

For any request you make into the maesn API this is the header that authenticates yourself as a user of the maesn API. This is the API key that you get when you sign up for an account with maesn.

Please contact us at the following [link](https://www.maesn.com/contact/) to get started.
We will get in touch with you to create an account and provide you with an API key.

## X-ACCOUNT-KEY header

When trying to access your end user's information in the target system, you will only be allowed to do so, if the end user went through the registration flow and authenticated to the target system, and you stored the `X-ACCOUNT-KEY` to use with these requests.

Every account key is unique to the end user and the target system, so an end user may have multiple of these depending on how many target systems they have authenticated to.

End user authentication is done through the `/auth/:TARGET_SYSTEM` endpoint.

```bash theme={null}
curl --request GET \
  --url 'https://api.maesn.dev/auth/:TARGET_SYSTEM?callbackUrl=YOUR_CALLBACK_URL' \
  -H 'x-api-key: YOUR_API_KEY'
```

Replace `:TARGET_SYSTEM` with the target system you want to authenticate to. For example, to authenticate to Xero, replace `:TARGET_SYSTEM` with `xero`.

You can send the callback URL as a query parameter to the `/auth/:TARGET_SYSTEM` endpoint. This will redirect the user back to your system after the authentication flow is complete.
You can also send a cancelCallbackUrl as a query parameter in cases where the user has to enter their API Key into our submission flow where they can cancel the flow.
If these values are not provided, the user will be redirected with the default callback values that you provided when we contacted you for account creation.

In case of `weclapp` and `xentral` you have the option to use a query parameter `tenantId` to autopopulate the given field in the submission page.

This endpoint will give back a URL that you need to show to the user to authenticate to the target system.

At the end of the flow we redirect the user back into your system based on a redirect URL you provide when we contact you for account creation.

At this point you will receive an account token that you can use to make API calls on behalf of the user.

For target systems that doesn't have an actual oAuth flow, there are two ways to generate an account key. Use the previously mentioned flow, and have a submission page shown to the user, or the `/auth/accounts/:TARGET_SYSTEM` endpoint can be used with a request body that contains the right values such as `apiKey`.
The second endpoint is appropriate when authenticating an end user without any UI interaction. For example, if you want to create the UI with your own user experience or have already collected all the client credentials at an earlier stage.
You can check out all the available target systems at the [Create account](/api-reference/auth/create-account) endpoint.

## Interactive Authentication Flow

In some supported systems, users must select a specific environment or company to complete their integration.

You can either:

* Pass these values manually as query parameters in each API request
* Or use the **Interactive Authentication Flow**

When `environmentSelection=true` is set in the query, the user is redirected to a selection page where they choose their environment or company. Once selected, those values are stored for future requests — so you don’t need to send them again.

Using the Interactive Authentication Flow ensures a consistent authentication experience across all systems — whether or not the end user needs to make a selection. This simplifies your implementation by removing the need to build custom selection steps into your own flow.

If you use the Interactive Authentication Flow but also send the `environment` or `company` parameters manually, those values will overwrite the ones stored for the user.

This flow also supports `callbackUrl` and `cancelCallbackUrl`, which define where the user is redirected after completing or cancelling the flow.

You can also customize the UI of the selection page to match your own branding and provide a seamless user experience.

**Note:** The Interactive Authentication Flow is only available for the following target systems:

* `businesscentral`
* `datev-uo`
* `datev-rewe`
* `datev-uo-longtoken`
* `datev-rewe-longtoken`
* `datev-rewe-export`
* `exact-nl`
* `moneybird`
* `sage-active-de`
* `sage-active-es`
* `sage-active-fr`
* `twinfield`

Please ensure that the *companyId* query parameter is not set when using interactive authentication with DATEV long tokens, as it may prevent the flow from working correctly.

## Headless Authentication flow

Some of the supported systems have an API key approach instead of the oAuth flow. In these cases maesn provides a UI page where the user can enter their API key and authenticate to the target system.
We offer the flexibility to bypass this UI page by implementing our Headless Authentication flow, which returns the account key directly in the API response.
There is a POST `/auth/accounts/:TARGET_SYSTEM` endpoint that can be used to authenticate the user without using the UI page.
This endpoint requires a body with all the required fields, and will send back the account key in the response.

**Note:** This flow is only available for the following target systems:

* `abaconnect`
* `buchhaltungsbutler-api`
* `holded`
* `sevdesk`
* `snelstart`
* `weclapp`
* `xentral`

## Page Design for Authentication pages

The authentication pages provided by maesn can be customized to match your brand's look and feel.
At the moment there is no way for you to change it, if you provide us the following values we can add them for you:

* Background color code
* Submit Button color code
* Text color code
* Input field background color code
* SVG logo
* Cancel Button color code
* Error Text color

## Signed Callbacks

Signed callbacks let you verify that redirect requests genuinely originate from Maesn. When enabled, each callback includes an HMAC-SHA256 signature you can validate server-side.

<Steps>
  <Step title="Generate a signing secret">
    Call `POST /tenant/signing-secret` to generate a secret for your tenant.

    ```bash theme={null}
    POST /tenant/signing-secret
    ```

    <Warning>
      This is the **only time** the secret is returned — there is no GET endpoint. Store it securely immediately.
      If you lose your secret, rotate it by calling the endpoint again. Be aware that rotation **immediately invalidates** the old secret, so update your configuration before rotating.
    </Warning>
  </Step>

  <Step title="Enable signature on authentication">
    Pass `include_signature=true` as a query parameter when calling `GET /auth/{target-system}`.

    ```
    GET /auth/{target-system}?include_signature=true
    ```

    <Warning>
      If no signing secret has been generated for your tenant, setting `include_signature=true` will return an error.
    </Warning>
  </Step>

  <Step title="Verify the signature on callback">
    Your callback URL will receive the following query parameters:

    ```
    https://your-app.com/callback?accountKey=...&ts=<timestamp>&maesn_signature=<hmac>
    ```

    | Parameter         | Description                                   |
    | ----------------- | --------------------------------------------- |
    | `accountKey`      | The account key for the authenticated tenant  |
    | `ts`              | Timestamp of when the account key was created |
    | `maesn_signature` | HMAC-SHA256 signature to verify               |

    Use the following logic to validate the signature:

    ```javascript theme={null}
    const crypto = require('crypto');

    const { accountKey, ts, maesn_signature } = req.query;

    // Reject callbacks older than 5 minutes
    const age = Math.abs(Date.now() / 1000 - parseInt(ts));
    if (age > 300) throw new Error('Callback expired');

    // Recompute the expected signature
    const payload = `accountKey=${accountKey}&ts=${ts}`;
    const expectedSig = crypto
      .createHmac('sha256', Buffer.from(secret, 'hex'))
      .update(payload)
      .digest('hex');

    const isValid = expectedSig === maesn_signature;
    ```
  </Step>
</Steps>
