fepli
REST API

Authentication

The fepli API authenticates with bearer tokens. A token acts either as a colleague or as a service account, and it is either read-only or read-write.

Sending a token

Put the token into the Authorization header with the Bearer scheme:

Authenticated request

curl https://ferienpass-musterstadt.de/api/me \
  -H "Authorization: Bearer pat-3kT9wQ2mZx7LpR4vN8bYc1Hd.f0Jq…"

A token looks like pat- or svc-, followed by a 24-character locator, a dot and a 64-character secret. fepli stores only a hash of the secret, so a token is shown once, when it is created, and can't be looked up again. If you lose one, revoke it and create a new one.

Two kinds of tokens

Personal access tokenService account token
Prefixpat-svc-
Acts asthe colleague who created it, with their rolesthe service account, with the roles configured for it
Created underuser menu → Passwort ändernAPI-TokensEinstellungen → Integrationen → API → Service-Accounts (super admins), or the command line
Use it fortrying things out, personal scriptsintegrations, scheduled jobs, AI agents: anything that should keep working when people change jobs

Both kinds can have a label and an expiry date. The admin shows when each token was last used, to within five minutes.

Read and write access

Every token carries a scope:

  • api:read allows only GET requests.
  • api:write also allows POST, PATCH and DELETE: creating, changing, deleting and moving records through their workflow.

You choose the scope when you create the token (Nur lesen or Lesen und schreiben). A read-only token is refused on every POST, PATCH and DELETE before anything else runs, whatever roles its owner has:

403 Forbidden

{
  "type": "/errors/403",
  "title": "An error occurred",
  "status": 403,
  "detail": "This token is read-only. Mint one with write access to change anything."
}

For service accounts there is a second limit. The account's access level (read or write) caps every token it holds. A token created with write access for an account that was later restricted to read can only read.

The scope decides whether a token may read or write at all. What it may read or write is decided by the roles of the person or service account behind it, exactly as in the admin. See Permissions.

Call GET /me to see a token's scopes and effective access:

GET /me (excerpt)

{
  "scopes": ["api:read", "api:write"],
  "access": "write"
}

Public access

One part of the API needs no token: GET /offers and GET /offers/{uuid} return the published offers of the editions that are online, the ones the public website shows. Offers published with a private link are never returned without a token. Anonymous callers get the public fields only; the internal ones, such as comment, contact or transitions, are left out.

A municipality can switch public access off under Einstellungen → Integrationen → API → Öffentlicher Zugriff. Then every request needs a token, and anonymous requests get a 401.

Anonymous requests have a strict rate limit. Cache the responses on your side.

Older tokens

Personal tokens created with earlier versions of fepli carry the old scope api:offer:read. They keep working, but only for GET /offers and GET /offers/{uuid}. Every other endpoint answers 403. Create a new token to use the rest of the API.

When authentication fails

StatusCause
401 UnauthorizedThe token is malformed, unknown or expired (Token expired), its service account is disabled (Service account disabled), or, for a personal token, its owner's account is suspended or their e-mail address is blocked. The body is empty; the reason is in the WWW-Authenticate response header. A 401 also answers anonymous requests to anything other than the public offers, and every anonymous request when public access is switched off.
403 ForbiddenThe token is valid, but it may not do this: it is read-only and the request writes, it is an older offers-only token, or its owner lacks the role for this endpoint. A write without any token is refused with 403 as well. A read-only token and a missing token get a detail that says so; a missing role gets Access Denied.
404 Not FoundThe API is switched off for this municipality. 404 is also the answer for records that don't exist or that you may not see. See Permissions.

A token only works for the municipality it was created in. On a multi-tenant installation, a token from one municipality is unknown to all others.

Keeping tokens safe

  • Never put a token into browser or app code. Anyone can read it there. To show offers publicly, you don't need a token. For anything else, call the API from your server.
  • Give each integration its own token, with a label you'll recognise later. Then you can revoke one without breaking the others.
  • Prefer read-only tokens. Most integrations and every support agent that only answers questions can do their work with read access.
  • Set an expiry date for tokens that are meant to be temporary.
  • Revoke a token in the admin as soon as it is no longer needed or may have leaked. Revoking takes effect immediately.

Was this page helpful?