Authentication
Get a session token with auth/login, create integration tokens with limited abilities and use them securely.
All API routes, apart from a few public ones (status, ping, pricing, auth/login, auth/demo), require a bearer token in the Authorization header.
GET /v1/auth/me HTTP/1.1
Host: api.novafisko.com
Authorization: Bearer 57|n8Yw2c0vXk4JrPq1LmZs
Accept: application/json
NovaFisko distinguishes two kinds of tokens.
| Type | Obtained through | Scope | Usage |
|---|---|---|---|
| Session token | POST /v1/auth/login |
All of the user's rights | NovaFisko applications, personal scripts |
| Integration token | POST /v1/auth/tokens |
Chosen abilities: read, write, sync |
Connecting another solution, server to server |
In both cases, the token acts on behalf of a user: it sees the firms and companies that user has access to, no more and no less. An inaccessible company responds 404, never 403, so as not to reveal its existence.
Session token
Log in
curl -X POST https://api.novafisko.com/v1/auth/login \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "claire.dumont@fiduciaire-exemple.be",
"password": "votre-mot-de-passe",
"device_name": "script-export-mensuel"
}'
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | yes | The user's address |
password |
string | yes | Password |
device_name |
string, 100 characters max | no | Name given to the token, api by default |
Response 201:
{
"token": "57|n8Yw2c0vXk4JrPq1LmZs",
"user": {
"id": 12,
"name": "Claire Dumont",
"email": "claire.dumont@fiduciaire-exemple.be",
"locale": "fr",
"is_platform_admin": false,
"firms": [
{"public_token": "Fd7hQ2mN8sXa", "name": "Fiduciaire Exemple", "role": "admin"}
],
"managed_firms": [
{"public_token": "Fd7hQ2mN8sXa", "name": "Fiduciaire Exemple"}
]
}
}
Incorrect credentials return 422 with an error on the email field. The route is limited to 20 requests per minute and per IP address. After 10 failures, every attempt is refused for 5 minutes.
Users of a Novadesko accounting firm log in with their Novadesko credentials. NovaFisko checks them in read-only mode, then mirrors the firm, its members and its companies at each login.
Get the current user
GET /v1/auth/me returns the same user object as the login, with the addition of is_demo (true for a user of the demo firm). It is the ideal call to check that a token is still valid.
Log out
POST /v1/auth/logout revokes the token used for the call and responds 204 with no body.
Integration tokens
An integration token is designed to be handed to another solution. It carries a name, a list of abilities, an optional expiry date and the date it was last used.
Abilities
| Ability | Allows |
|---|---|
read |
All GET and HEAD requests |
write |
POST, PUT, PATCH and DELETE requests |
sync |
The companies/{company}/sync/* routes (bootstrap, pull, push, status, conflicts), whatever the method |
The six offline synchronisation routes only require sync. A connector that merely follows changes with sync/pull therefore needs neither read nor write. The POST companies/{company}/sync/novadesko route, which reruns the import from Novadesko, is not one of them: it falls under write.
Create a token
Creation requires a session token: an integration token cannot create other tokens.
curl -X POST https://api.novafisko.com/v1/auth/tokens \
-H "Authorization: Bearer 57|n8Yw2c0vXk4JrPq1LmZs" \
-H "Content-Type: application/json" \
-d '{
"name": "Connecteur ERP Atelier",
"abilities": ["read", "write"],
"expires_in_days": 365
}'
| Field | Type | Required | Description |
|---|---|---|---|
name |
string, 100 characters max | yes | Readable name, shown in the list |
abilities |
array | yes, at least 1 value | Among read, write, sync |
expires_in_days |
integer from 1 to 730, or null |
no | Lifetime; null or absent: no expiry |
Response 201:
{
"token": "83|4Hq7ZtVb2Mx9KcLp0RsWyE1uNaJd6FgT",
"integration_token": {
"id": 83,
"name": "Connecteur ERP Atelier",
"abilities": ["read", "write"],
"created_at": "2026-10-05T08:30:11+00:00",
"expires_at": "2027-10-05T08:30:11+00:00",
"last_used_at": null
}
}
A user can hold at most 50 integration tokens. Beyond that, creation responds 422 with the token_limit_reached code. The route is limited to 20 creations per minute.
The token value is shown only once, in this response. NovaFisko only keeps a hash of it. If you lose it, delete the token and create another one.
List tokens
curl https://api.novafisko.com/v1/auth/tokens \
-H "Authorization: Bearer 57|n8Yw2c0vXk4JrPq1LmZs"
{
"data": [
{
"id": 83,
"name": "Connecteur ERP Atelier",
"abilities": ["read", "write"],
"created_at": "2026-10-05T08:30:11+00:00",
"expires_at": "2027-10-05T08:30:11+00:00",
"last_used_at": "2026-10-05T09:02:47+00:00"
}
]
}
Only your own integration tokens are listed. The session tokens of the applications do not appear.
Revoke a token
curl -X DELETE https://api.novafisko.com/v1/auth/tokens/83 \
-H "Authorization: Bearer 57|n8Yw2c0vXk4JrPq1LmZs"
The response is 204. The token stops working immediately. An unknown identifier, or one that is not one of your integration tokens, responds 404.
Authentication errors
| Status | code |
Cause | What to do |
|---|---|---|---|
401 |
absent | Token missing, revoked or expired | Get a new token |
403 |
token_ability_missing |
The integration token lacks the required ability | Create a token with the ability given in required_ability |
403 |
session_token_required |
Route reserved for session tokens (auth/tokens) |
Use a token issued by auth/login |
403 |
demo_mode |
External effect attempted from the demo firm | Test this action on a real firm |
422 |
token_limit_reached |
50 integration tokens already exist | Revoke unused tokens |
422 |
absent | Incorrect credentials or too many attempts | Read errors.email |
Example of a refusal for a missing ability:
{
"message": "Ce jeton n'a pas la capacité requise pour cette action.",
"code": "token_ability_missing",
"required_ability": "write"
}
Best practices
- One token per integration. You can revoke one without interrupting the others, and the last-used column stays readable.
- As few abilities as possible. A reporting tool only needs
read. - An expiry. Set
expires_in_daysand schedule the renewal before the deadline. - A dedicated user. Create a team member in the firm reserved for the integration, with the strictly necessary role. The history will clearly show what the integration did.
- Encrypted storage. Keep the token in a secrets manager or an environment variable, never in source code, a Git repository or an application running in your customers' browser.
- HTTPS only. Never send the token over an unencrypted connection and do not put it in a URL.
If a token may have leaked, revoke it right away with DELETE /v1/auth/tokens/{id}. Then check the History tab of the companies concerned to review the actions performed.