---
title: "Authentication · EenFactuurMaken.nl"
description: "How to authenticate with the EenFactuurMaken.nl REST API using an API key (Bearer or X-API-Key), what a key can't do and how to keep keys safe."
url: "https://eenfactuurmaken.nl/en/docs/api/authentication"
markdown_url: "https://eenfactuurmaken.nl/en/docs/api/authentication.md"
language: "en-GB"
---

# Authentication

How to authenticate with the EenFactuurMaken.nl REST API using an API key (Bearer or X-API-Key), what a key can't do and how to keep keys safe.

Every API request needs an **API key**. Create one under **Settings → API & AI** (see [API keys and apps](https://eenfactuurmaken.nl/en/docs/security/api-keys)). A key starts with `efm_`.

## Sending the key

Preferably use the `Authorization` header:

```bash
curl https://eenfactuurmaken.nl/api/v1/invoices \
  -H "Authorization: Bearer efm_your_key"
```

Can't your tool send Bearer tokens? Use `X-API-Key` instead:

```bash
curl https://eenfactuurmaken.nl/api/v1/invoices \
  -H "X-API-Key: efm_your_key"
```

In JavaScript (Node 18 or newer):

```js
const res = await fetch('https://eenfactuurmaken.nl/api/v1/me', {
  headers: { Authorization: `Bearer ${process.env.EENFACTUURMAKEN_API_KEY}` },
})
if (!res.ok) throw new Error((await res.json()).data?.code)
console.log(await res.json())
```

In Python:

```python
import os, requests

r = requests.get(
    "https://eenfactuurmaken.nl/api/v1/me",
    headers={"Authorization": f"Bearer {os.environ['EENFACTUURMAKEN_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
print(r.json())
```

## Authentication errors

| Status | Code | Meaning |
| --- | --- | --- |
| 401 | `unauthenticated` | No key was sent. |
| 401 | `invalid_api_key` | The key is wrong, revoked or expired. |
| 403 | `session_required` | This only works in the web app (see below). |
| 429 | `rate_limited` | More than 120 requests a minute with this key. Wait the number of seconds in the `Retry-After` header. |

## What only works in the web app?

To protect you if a key leaks, these actions don't work with an API key (`403 session_required`):

- changing payment details: `iban`, `bic`, `bankAccountName`, `email` (reply-to address) and `defaultPaymentLink` through `PATCH /business`;
- starting, cancelling or resuming your subscription;
- security (password, 2FA, passkeys, devices, security log, API keys, connected apps) and deleting your account;
- the welcome guide.

## Sessions and OAuth

- The web app uses a session cookie. That comes with an extra check on the `Origin` header (`403 bad_origin`) against CSRF. With an API key this doesn't affect you.
- OAuth tokens are only for the MCP server. See [MCP server](https://eenfactuurmaken.nl/en/docs/mcp#oauth).

## Working safely

- Put the key in an environment variable or secrets store, never in your code or in a public repository.
- Only use the API from your server, not from a browser: that would expose your key.
- Create a separate key per integration, with an expiry date. Then you can revoke one without affecting the rest.
- Has a key leaked? [Revoke it right away](https://eenfactuurmaken.nl/en/docs/security/api-keys#revoke).

Last updated on 13 October 2026
