Flowdue API v1

Die Flowdue-API stellt Authentifizierung, Invite-Register und Lead-Erfassung für das Frontend bereit – per Cookie-Session und CSRF-Schutz.

Session statt API-Key. Alle mutierenden Endpunkte brauchen das X-CSRF-Token-Headerfeld plus Cookies (credentials: "include").

Authentifizierung

Anmeldung per E-Mail + Passwort gegen POST /auth/login. Bei Erfolg setzt der Server zwei HttpOnly-Cookies: accessToken (15 Minuten, Path=/) und refreshToken (7 Tage, Path=/api/v1/auth/refresh). Der Access-Token kann alternativ als Authorization: Bearer-Header gesendet werden.

X-CSRF-Token: <Wert aus _csrf-Cookie>
Login-Fehler antworten immer generisch mit 401 INVALID_CREDENTIALS – ohne zu verraten, ob E-Mail, Passwort oder Kontostatus falsch sind.

Basis-URL

https://localhost/api/v1  (lokal, produktiv eigene Domain)

Alle Endpunkte liefern ausschließlich JSON. Fehler folgen dem Format aus Fehler.

Rate-Limits

LimitWert
Global100 / 15 Minuten pro IP
Login / Admin-Login5 / 15 Minuten pro E-Mail + IP
Register3 / Stunde
Reset-Password5 / 15 Minuten
Leads10 / Stunde

Bei Überschreitung antwortet die API mit HTTP 429 und dem Code RATE_LIMITED.

Fehler

Fehler werden einheitlich im folgenden Format zurückgegeben:

{
  "success": false,
  "code": "INVALID_CREDENTIALS",
  "message": "E-Mail oder Passwort ist ungültig."
}
HTTPCodeBedeutung
400VALIDATION_ERROR / EMAIL_MISMATCH / INVALID_TOKENUngültige Eingabe oder abgelaufener Link
401INVALID_CREDENTIALS / UNAUTHORIZEDLogin falsch oder keine Session
403FORBIDDEN / INVALID_CSRFKeine Berechtigung oder CSRF fehlt
404INVITE_NOT_FOUNDEinladung unbekannt
409INVITE_USED / EMAIL_EXISTSEinladung verbraucht oder Mail vergeben
410INVITE_EXPIREDEinladung abgelaufen (48h)
428NEED_RECONSENTDatenschutz erneut zustimmen
429RATE_LIMITEDRate-Limit überschritten

Auth

GET/api/v1/auth/csrf-token

Setzt das lesbare _csrf-Cookie (5h). Antwort: { success: true }.

POST/api/v1/auth/login

Body: { email, password }. Antwort 200: { success: true, user } plus Cookies. Konten mit Status pending werden mit 401 abgelehnt.

POST/api/v1/auth/admin-login

Wie Login, lässt aber nur role: admin durch (sonst generisch 401).

GET/api/v1/auth/verify

Session-Boot (Auth nötig). Antwort: { user, features }.

POST/api/v1/auth/refresh

Rotiert das Refresh-Token (liest refreshToken-Cookie, braucht CSRF-Header). Wiederverwendung sperrt alle Sessions.

POST/api/v1/auth/logout

Meldet die aktuelle Session ab (Auth nötig). POST /auth/logout-all beendet alle Sessions des Users.

POST/api/v1/auth/forgot-password

Body: { email }. Antwort immer generisch (kein User-Enumeration). Token 1h gültig.

Body (JSON)

POST /api/v1/auth/reset-password
{ "token": "…", "password": "Neues!Passwort1" }

Setzt ein neues Passwort (starke Regeln wie Register) und meldet alle Sessions ab. Kein Auto-Login.

POST/api/v1/auth/re-consent

Body: { email, password, acceptPrivacyVersion }. Login-Weiterführung bei aktualisierter Datenschutzerklärung.

Register & Invites

Registrierung ist ausschließlich per Einladung möglich (48h, einmalig, an E-Mail gebunden).

GET/api/v1/auth/invite/:token

Prüft einen Invite-Link. Antwort 200: { email, expiresAt }.

POST/api/v1/auth/register

Body: { inviteToken, firstName, lastName, company, email, password, acceptTerms }. Passwort: min. 12 Zeichen, Groß-/Kleinbuchstaben, Zahl, Sonderzeichen. Antwort 201, Status pending – kein Auto-Login.

Antwort (201)

{
  "success": true,
  "user": { "id": "…", "email": "…", "status": "pending", … }
}

Admin

Alle Admin-Endpunkte brauchen eine Admin-Session (role: admin).

POST/api/v1/admin/invites

Body: { email }. Erzeugt eine Einladung, Antwort mit inviteLink (/register?invite=…).

Leads

POST/api/v1/leads

Erstgespräch-Anfrage (10/h). Body: { firstname, lastname, company, role, phone, email, tool, invoices, revenue }.

Code-Beispiele

cURL – Login + Verify

# 1. CSRF-Cookie holen
curl -c jar.txt https://localhost/api/v1/auth/csrf-token
CSRF=$(grep _csrf jar.txt | awk '{print $NF}')

# 2. Login
curl -b jar.txt -c jar.txt -X POST https://localhost/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: $CSRF" \
  -d '{"email":"admin@flowdue.local","password":"…"}'

# 3. Session prüfen
curl -b jar.txt https://localhost/api/v1/auth/verify

JavaScript (fetch)

const res = await fetch("https://localhost/api/v1/auth/verify", {
  credentials: "include",
});
const { user } = await res.json();
console.log(user);

Admin – Invite erzeugen

const res = await fetch("https://localhost/api/v1/admin/invites", {
  method: "POST",
  credentials: "include",
  headers: { "Content-Type": "application/json", "X-CSRF-Token": csrf },
  body: JSON.stringify({ email: "neu@beispiel.de" }),
});
const { inviteLink } = await res.json();