InvoFlux External Punch API

Version 2.1 · Stand: 08.07.2026

Inhalt

InvoFlux External Punch API Documentation

Version: 2.1
Datum: 08. Juli 2026


Übersicht

Die InvoFlux External Punch API ermöglicht externen Systemen den Zugriff auf die Zeiterfassungsfunktionen von InvoFlux. Alle Endpoints sind token-basiert abgesichert und verwenden REST-Prinzipien mit JSON als Datenformat.

Seit Version 2.0 gibt es zusätzlich zur klassischen Zeiterfassung (Endpoints 1–4) einen Reservierungs-Mechanismus (Endpoints 5–7) für Systeme wie Terminbuchungs-Tools, die einen Mitarbeiter für einen zukünftigen Zeitraum als "verplant" markieren wollen, ohne direkt echte Arbeitszeit zu buchen. Siehe Reservierungen für die Details.

Seit Version 2.1 gibt es zusätzlich einen Abwesenheits-Endpunkt (Endpoint 8), mit dem Terminbuchungs-Systeme mehrtägig im Voraus prüfen können, an welchen Tagen ein Mitarbeiter wegen Urlaub, Zeitausgleich o.ä. nicht verfügbar ist — ohne den konkreten Grund zu erfahren. Siehe Abwesenheiten für die Details.

Basis-Informationen

Wichtig für Integrationen: Die Base URL ist pro InvoFlux-Installation unterschiedlich (jeder Kunde hat seine eigene Domain). Ein externes System, das mehrere InvoFlux-Kunden anbindet, muss die Base URL pro Kunde/Verbindung konfigurierbar halten — sie darf nicht hartkodiert werden.


Authentifizierung

Alle API-Requests erfordern einen gültigen API-Token im HTTP-Header:

X-API-TOKEN: <ihr-api-token>

Der Token ist pro Benutzer vergeben (nicht pro Firma/Installation) — jeder Mitarbeiter, dessen Daten über die API gelesen oder geschrieben werden sollen, braucht grundsätzlich seinen eigenen Token, sofern die aufrufende Aktion sich auf "den aktuell authentifizierten Benutzer" bezieht (Endpoints 1–3). Bei Endpoints, die einen Ziel-Benutzer per UUID adressieren (Endpoints 4–7), kann ein Admin/TimeAdmin-Token verwendet werden, das für alle Mitarbeiter gilt.

Token generieren

  1. Als Benutzer mit ROLE_MANAGER oder ROLE_ADMIN in InvoFlux einloggen
  2. Profil aufrufen (/profile/edit)
  3. Im Abschnitt "API-Zugriff" den Button "API-Token erzeugen" klicken
  4. Token kopieren und sicher aufbewahren

Fehlerhafte Authentifizierung

Bei fehlendem oder ungültigem Token:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "Missing X-API-TOKEN header"
}

oder

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "Invalid API token"
}

workStatus-Enum

Der Arbeitsmodus (workStatus) eines Mitarbeiters kann genau einer der folgenden Werte sein:

WertBedeutung
OFFICEIm Büro (Default)
AT_CUSTOMERBeim Kunden
IN_PROJECTIm Projekt
IN_MEETINGIm Meeting
BUSINESS_TRIPDienstreise

Korrektur ggü. Version 1.0: HOME_OFFICE existiert nicht als workStatus-Wert und wurde aus dieser Dokumentation entfernt. Ein Request mit einem unbekannten workStatus-Wert wird von der API stillschweigend auf OFFICE zurückgesetzt (kein Fehler).

Urlaub und Krankheit sind kein workStatus — sie werden über ein separates Abwesenheits-System verwaltet und tauchen im /status-Endpoint als eigenes Feld absence auf (siehe unten), nicht als workStatus-Wert.


Endpoints

1. Status abrufen GET

Liefert den aktuellen Arbeitsstatus des authentifizierten Benutzers für den heutigen Tag.

Endpoint: GET /ext-api/punch/status

Request-Header:

X-API-TOKEN: <api-token>
Accept: application/json

Query-Parameter: Keine

Erfolgreiche Antwort (200 OK)

Benutzer arbeitet aktuell (im Büro, verfügbar):

{
  "status": "WORKING",
  "lastEventType": "WORK_START",
  "lastEventTime": "2026-01-29T08:15:00+01:00",
  "workStartTime": "2026-01-29T08:00:00+01:00",
  "workStatus": "OFFICE",
  "absence": null,
  "available": true
}

Benutzer arbeitet aktuell, aber im Projekt (nicht kurzfristig verfügbar):

{
  "status": "WORKING",
  "lastEventType": "WORK_START",
  "lastEventTime": "2026-01-29T10:00:00+01:00",
  "workStartTime": "2026-01-29T08:00:00+01:00",
  "workStatus": "IN_PROJECT",
  "absence": null,
  "available": false
}

Benutzer in Pause:

{
  "status": "ON_BREAK",
  "lastEventType": "BREAK_START",
  "lastEventTime": "2026-01-29T12:00:00+01:00",
  "workStartTime": "2026-01-29T08:00:00+01:00",
  "workStatus": "OFFICE",
  "absence": null,
  "available": false
}

Benutzer hat heute noch nicht gearbeitet:

{
  "status": "NOT_STARTED",
  "lastEventType": null,
  "lastEventTime": null,
  "workStartTime": null,
  "workStatus": null,
  "absence": null,
  "available": false
}

Benutzer hat Arbeit beendet:

{
  "status": "FINISHED",
  "lastEventType": "WORK_END",
  "lastEventTime": "2026-01-29T16:30:00+01:00",
  "workStartTime": null,
  "workStatus": null,
  "absence": null,
  "available": false
}

Benutzer hat heute genehmigten Urlaub/ist krankgemeldet (unabhängig vom Stempel-Status):

{
  "status": "NOT_STARTED",
  "lastEventType": null,
  "lastEventTime": null,
  "workStartTime": null,
  "workStatus": null,
  "absence": "VACATION",
  "available": false
}

Status-Werte

WertBedeutung
NOT_STARTEDHeute noch keine Arbeit erfasst
WORKINGAktuell am Arbeiten
ON_BREAKAktuell in Pause
FINISHEDArbeit für heute beendet

Response-Felder

FeldTypBeschreibung
statusstringSiehe Tabelle oben
lastEventTypestring|nullTyp des letzten Zeiterfassungs-Events (WORK_START, WORK_END, BREAK_START, BREAK_END)
lastEventTimestring|nullZeitpunkt des letzten Events (ISO 8601)
workStartTimestring|nullZeitpunkt des ersten WORK_START am heutigen Tag, falls aktuell WORKING/ON_BREAK
workStatusstring|nullAktueller Arbeitsmodus, siehe workStatus-Enum. null, wenn heute noch keine Arbeit erfasst oder bereits beendet
absencestring|nullTyp einer genehmigten Abwesenheit am heutigen Tag (z.B. VACATION, SICK, HOLIDAY), sonst null
availablebooleanKonsolidiertes Verfügbarkeits-Flag für Kurzfrist-Buchungen: true nur wenn status = WORKING und workStatus = OFFICE und absence = null

available wurde speziell für Systeme eingeführt, die kurzfristig entscheiden müssen, ob ein Mitarbeiter spontan ansprechbar ist (z.B. Terminbuchungs-Tools). Es fasst alle relevanten Bedingungen in einem einzigen Boolean zusammen, damit Integrationen nicht selbst status/workStatus/absence kombinieren müssen.

Beispiel-Request (cURL)

curl -X GET https://ihre-domain.invoflux.de/ext-api/punch/status \
  -H "X-API-TOKEN: abc123def456..." \
  -H "Accept: application/json"

1b. Status eines Mitarbeiters per UUID abrufen GET

Gleiche Response wie oben, aber für einen beliebigen Mitarbeiter (per externalUuid), aufrufbar mit einem Admin/TimeAdmin-Token.

Endpoint: GET /ext-api/punch/status/{uuid}

Erfolgreiche Antwort (200 OK): Wie bei Endpoint 1, zusätzlich mit Feld user (die angefragte UUID).

2. Arbeit starten POST

Startet eine Arbeitszeit für den authentifizierten Benutzer.

Endpoint: POST /ext-api/punch/work-start

Request-Header:

X-API-TOKEN: <api-token>
Content-Type: application/json
Accept: application/json

Request-Body (JSON, optional):

{
  "workStatus": "OFFICE",
  "projectId": 123
}

Body-Parameter

ParameterTypPflichtBeschreibung
workStatusstringNeinArbeitsmodus (Default: OFFICE). Siehe workStatus-Enum
projectIdintegerNeinID eines aktiven Projekts. Nur bei workStatus: IN_PROJECT sinnvoll

Erfolgreiche Antwort (200 OK)

Mit Projekt:

{
  "success": true,
  "type": "WORK_START",
  "occurredAt": "2026-01-29T08:00:00+01:00",
  "workStatus": "IN_PROJECT",
  "project": {
    "id": 123,
    "name": "Website-Relaunch"
  }
}

Ohne Projekt:

{
  "success": true,
  "type": "WORK_START",
  "occurredAt": "2026-01-29T08:00:00+01:00",
  "workStatus": "OFFICE",
  "project": null
}

Fehlerfälle

Projekt nicht gefunden (404 Not Found):

{
  "error": "Project not found"
}

Beispiel-Request (cURL)

curl -X POST https://ihre-domain.invoflux.de/ext-api/punch/work-start \
  -H "X-API-TOKEN: abc123def456..." \
  -H "Content-Type: application/json" \
  -d '{
    "workStatus": "OFFICE",
    "projectId": 123
  }'

3. Arbeit beenden POST

Beendet eine laufende Arbeitszeit für den authentifizierten Benutzer.

Endpoint: POST /ext-api/punch/work-end

Request-Header:

X-API-TOKEN: <api-token>
Accept: application/json

Request-Body: Leer (kein Body erforderlich)

Erfolgreiche Antwort (200 OK)

{
  "success": true,
  "type": "WORK_END",
  "occurredAt": "2026-01-29T16:30:00+01:00"
}

Beispiel-Request (cURL)

curl -X POST https://ihre-domain.invoflux.de/ext-api/punch/work-end \
  -H "X-API-TOKEN: abc123def456..." \
  -H "Accept: application/json"

4. Manuelle Tagesbuchung erstellen POST

Erstellt eine vollständige Tagesbuchung für einen beliebigen Benutzer (per UUID). Dieser Endpoint ist für externe Systeme gedacht, die nachträglich (rückwirkend) Zeiten importieren möchten — nicht für zukünftige Termine/Reservierungen. Für zukünftige Zeiträume siehe Reservierungen.

Endpoint: POST /ext-api/punch/entry

Request-Header:

X-API-TOKEN: <api-token>
Content-Type: application/json
Accept: application/json

Request-Body (JSON):

{
  "user": "8c88c0c0-1234-4abc-9def-0123456789ab",
  "date": "2026-01-28",
  "start": "08:00",
  "end": "16:30",
  "breakMinutes": 30,
  "projectId": 123,
  "workStatus": "OFFICE",
  "reason": "Import aus externem System"
}

Body-Parameter

ParameterTypPflichtBeschreibung
userstringJaUUID des Benutzers (Feld externalUuid in der User-Tabelle)
datestringJaDatum im Format Y-m-d (z.B. 2026-01-28)
startstringJaStartzeit im Format HH:mm (z.B. 08:00)
endstringJaEndzeit im Format HH:mm (z.B. 16:30)
breakMinutesintegerNeinPausenzeit in Minuten (Default: 0)
projectIdintegerNeinID eines aktiven Projekts
workStatusstringNeinArbeitsmodus (Default: OFFICE)
reasonstringJaBegründung für die manuelle Buchung (darf nicht leer sein)

Achtung: Dieser Endpoint erzeugt echte WORK_START/WORK_END-Events, die in die Tagesberechnung (plannedMinutes/netMinutes/overtimeMinutes) einfließen. Wird für denselben Tag später zusätzlich real gestempelt, werden beide Zeiträume addiert (InvoFlux erlaubt bewusst beliebig viele Stempel-Paare pro Tag, z.B. für private Unterbrechungen). Für reine "wird dieser Mitarbeiter zu diesem Zeitpunkt verplant, ohne dass real gearbeitete Zeit doppelt gezählt wird"-Anwendungsfälle den Reservierungs-Endpoint verwenden, nicht diesen.

Restriktionen

Für Benutzer ohne ROLE_TIMEADMIN / ROLE_ADMIN:

  1. Nur vergangene Tage: Das Datum muss in der Vergangenheit liegen
  2. Maximal 7 Tage zurück: Das Datum darf nicht älter als 7 Tage sein
  3. Keine bestehenden Buchungen: Für den Tag dürfen noch keine Zeitbuchungen existieren

Für Benutzer mit ROLE_TIMEADMIN / ROLE_ADMIN:

Keine Einschränkungen bei Datum/Vorbuchungen – auch zukünftige Daten werden angenommen (siehe Warnhinweis oben zur Doppelzählung).

Erfolgreiche Antwort (200 OK)

{
  "success": true,
  "user": "8c88c0c0-1234-4abc-9def-0123456789ab",
  "date": "2026-01-28",
  "plannedMinutes": 480,
  "netMinutes": 450,
  "overtimeMinutes": -30
}

Fehlerfälle

Fehlende Pflichtfelder (400 Bad Request):

{
  "error": "missing_fields",
  "message": "Fields \"user\", \"date\", \"start\", \"end\" are required."
}

Ungültiges Datumsformat (400 Bad Request):

{
  "error": "invalid_date",
  "message": "Invalid date format, expected Y-m-d."
}

Ungültiges Zeitformat (400 Bad Request):

{
  "error": "invalid_time",
  "message": "Invalid time format, expected HH:mm."
}

Endzeit vor oder gleich Startzeit (400 Bad Request):

{
  "error": "time_range_invalid",
  "message": "End time must be after start time."
}

Fehlende Begründung (400 Bad Request):

{
  "error": "missing_reason",
  "message": "A reason for the manual entry is required."
}

Benutzer nicht gefunden (404 Not Found):

{
  "error": "user_not_found",
  "message": "User with given UUID not found."
}

Projekt nicht gefunden/inaktiv (404 Not Found):

{
  "error": "project_not_found",
  "message": "Projekt nicht gefunden oder inaktiv."
}

Tag bereits gebucht – nur für Nicht-Admins (403 Forbidden):

{
  "error": "already_booked",
  "message": "Für diesen Tag existieren bereits Buchungen. Bitte kontaktiere einen Administrator für Korrekturen."
}

Datum liegt nicht in Vergangenheit – nur für Nicht-Admins (403 Forbidden):

{
  "error": "not_past",
  "message": "Manuelle Buchungen sind nur für vergangene Tage erlaubt."
}

Datum älter als 7 Tage – nur für Nicht-Admins (403 Forbidden):

{
  "error": "too_old",
  "message": "Manuelle Buchungen sind nur bis zu 7 Tage rückwirkend möglich."
}

Unerwarteter Server-Fehler (400 Bad Request):

{
  "error": "exception",
  "message": "Detaillierte Fehlermeldung..."
}

Beispiel-Request (cURL)

curl -X POST https://ihre-domain.invoflux.de/ext-api/punch/entry \
  -H "X-API-TOKEN: abc123def456..." \
  -H "Content-Type: application/json" \
  -d '{
    "user": "8c88c0c0-1234-4abc-9def-0123456789ab",
    "date": "2026-01-28",
    "start": "08:00",
    "end": "16:30",
    "breakMinutes": 30,
    "projectId": 123,
    "workStatus": "OFFICE",
    "reason": "Import aus externem Zeiterfassungssystem"
  }'

Reservierungen

Neu in Version 2.0.

Reservierungen bilden einen komplett anderen Anwendungsfall ab als entry (Endpoint 4): Ein externes Buchungssystem (z.B. ein Terminkalender) will einen Mitarbeiter für einen zukünftigen Zeitraum als "verplant" markieren, ohne dass diese Zeit automatisch als real gearbeitete Zeit in die Tagesberechnung einfließt — schließlich steht zum Buchungszeitpunkt noch nicht fest, ob der Mitarbeiter zum Termin überhaupt im Dienst sein wird.

Funktionsprinzip

  1. Das externe System legt per POST /ext-api/reservations eine Reservierung mit Status PENDING an. Es wird kein Zeiterfassungs-Event erzeugt.
  2. Ein interner InvoFlux-Cronjob prüft alle 5 Minuten fällige Reservierungen (deren Start erreicht ist) anhand der tatsächlichen Stempel-Historie:
    • War der Mitarbeiter zum exakten Reservierungs-Start-Zeitpunkt eingestempelt (offener WORK_START, kein WORK_END dazwischen)? → Reservierung wird CONFIRMED, und die Projektzeit wird ab diesem Zeitpunkt als Status-Wechsel auf der laufenden Schicht gebucht (workStatus: IN_PROJECT, kein eigenes, zusätzliches Zeitpaar — keine Doppelzählung).
    • War er nicht eingestempelt? → Reservierung wird CANCELLED, keine Zeit wird gebucht.
  3. Diese Prüfung ist ein einmaliger, historischer Zeitpunkt-Check exakt zum Reservierungsbeginn. Was der Mitarbeiter danach tut (z.B. normal weiterarbeiten, später auschecken) hat keinen Einfluss mehr auf das Ergebnis.
  4. Der Rückwechsel vom IN_PROJECT-Status zurück auf OFFICE (oder einen anderen Status) nach Ende der Reservierung erfolgt nicht automatisch — das macht der Mitarbeiter bewusst selbst über die normale Zeiterfassung, da InvoFlux nicht wissen kann, ob die tatsächliche Projektarbeit exakt zum geplanten Ende endet.

Reservierungs-Status

StatusBedeutung
PENDINGReservierung angelegt, Start noch nicht erreicht oder noch nicht geprüft
CONFIRMEDMitarbeiter war zum Start eingestempelt, Projektzeit wurde gebucht
CANCELLEDMitarbeiter war nicht eingestempelt, oder Reservierung wurde extern storniert

5. Reservierung anlegen POST

Endpoint: POST /ext-api/reservations

Request-Header:

X-API-TOKEN: <api-token>
Content-Type: application/json
Accept: application/json

Request-Body (JSON):

{
  "user": "8c88c0c0-1234-4abc-9def-0123456789ab",
  "date": "2026-07-10",
  "start": "10:00",
  "end": "12:00",
  "projectId": 123,
  "reason": "VQBooking: Kunde Müller GmbH – Beratungstermin",
  "externalRef": "vqbooking-booking-4711"
}

Body-Parameter

ParameterTypPflichtBeschreibung
userstringJaUUID des Benutzers (externalUuid)
datestringJaDatum im Format Y-m-d
startstringJaStartzeit im Format HH:mm
endstringJaEndzeit im Format HH:mm, muss nach start liegen
projectIdintegerNeinID eines aktiven Projekts. Ohne Angabe wird bei Bestätigung workStatus: IN_PROJECT ohne Projektbezug gebucht
reasonstringNeinFreitext, erscheint als Buchungsgrund, falls die Reservierung bestätigt wird
externalRefstringNeinFreie Referenz-ID des aufrufenden Systems (z.B. Buchungs-ID), rein informativ, für eigene Zuordnung

Erfolgreiche Antwort (201 Created)

{
  "success": true,
  "id": 42,
  "status": "PENDING"
}

id ist die InvoFlux-interne Reservierungs-ID — diese unbedingt speichern, sie wird für Abfrage und Stornierung benötigt.

Fehlerfälle

Analog zu Endpoint 4: missing_fields (400), user_not_found (404), invalid_date/invalid_time (400), time_range_invalid (400), project_not_found (404).

Beispiel-Request (cURL)

curl -X POST https://ihre-domain.invoflux.de/ext-api/reservations \
  -H "X-API-TOKEN: abc123def456..." \
  -H "Content-Type: application/json" \
  -d '{
    "user": "8c88c0c0-1234-4abc-9def-0123456789ab",
    "date": "2026-07-10",
    "start": "10:00",
    "end": "12:00",
    "reason": "VQBooking: Kunde Müller GmbH – Beratungstermin",
    "externalRef": "vqbooking-booking-4711"
  }'

6. Reservierung abrufen GET

Endpoint: GET /ext-api/reservations/{id}

Erfolgreiche Antwort (200 OK)

{
  "id": 42,
  "status": "CONFIRMED",
  "workDate": "2026-07-10",
  "startAt": "2026-07-10T10:00:00+02:00",
  "endAt": "2026-07-10T12:00:00+02:00",
  "checkedAt": "2026-07-10T10:00:12+02:00"
}

checkedAt ist null, solange die Reservierung noch PENDING ist (Start noch nicht erreicht/geprüft).

Fehlerfälle

Nicht gefunden (404 Not Found):

{
  "error": "not_found",
  "message": "Reservation not found."
}

7. Reservierung stornieren DELETE

Storniert eine noch nicht bestätigte Reservierung, z.B. weil die zugrunde liegende Buchung im externen System storniert oder verschoben wurde.

Endpoint: DELETE /ext-api/reservations/{id}

Erfolgreiche Antwort (200 OK)

{
  "success": true,
  "id": 42,
  "status": "CANCELLED"
}

Ist die Reservierung bereits CANCELLED, ist der Aufruf idempotent (gleiche 200-Antwort, kein Fehler).

Fehlerfälle

Reservierung bereits bestätigt (409 Conflict):

Wenn der Mitarbeiter bereits als anwesend erkannt und die Projektzeit real gebucht wurde, kann die Reservierung nicht mehr einfach zurückgenommen werden — die entsprechende Arbeitszeit ist inzwischen ein echter Zeiterfassungs-Eintrag.

{
  "error": "already_confirmed",
  "message": "Mitarbeiter war bereits eingebucht, Zeit wurde real gebucht. Storno nur über manuelle Korrektur möglich."
}

In diesem Fall muss die Korrektur der gebuchten Zeit manuell im InvoFlux-Backend durch einen Admin/TimeAdmin erfolgen.

Nicht gefunden (404 Not Found):

{
  "error": "not_found",
  "message": "Reservation not found."
}

Beispiel-Request (cURL)

curl -X DELETE https://ihre-domain.invoflux.de/ext-api/reservations/42 \
  -H "X-API-TOKEN: abc123def456..."

Abwesenheiten

Neu in Version 2.1.

Liefert für einen Mitarbeiter, an welchen Tagen innerhalb eines Zeitraums er nicht verfügbar ist (Urlaub, Krankheit, Berufsschule, Sonstiges, oder Zeitausgleich wegen Überstunden). Gedacht für Terminbuchungs-Systeme, die vor der Buchung mehrtägig im Voraus prüfen wollen, an welchen Tagen ein Mitarbeiter grundsätzlich in Frage kommt — im Unterschied zu /ext-api/punch/status/{uuid} (Endpoint 1b), das nur die aktuelle Kurzfrist-Verfügbarkeit für jetzt liefert.

Datenschutz: Diese API gibt bewusst keinen Grund und keinen Typ der Abwesenheit zurück — nur ob ein Tag verfügbar ist oder nicht. Damit werden keine gesundheitsbezogenen Daten (z.B. Krankmeldungen) an das externe System weitergegeben.

8. Abwesenheiten abfragen GET

Endpoint: GET /ext-api/absences/{uuid}?from=YYYY-MM-DD&to=YYYY-MM-DD

Request-Header:

X-API-TOKEN: <api-token>
Accept: application/json

Query-Parameter

ParameterTypPflichtBeschreibung
fromstringJaBeginn des Abfragezeitraums, Format Y-m-d
tostringJaEnde des Abfragezeitraums, Format Y-m-d, muss auf/nach from liegen

Der Zeitraum darf maximal 366 Tage umfassen.

Erfolgreiche Antwort (200 OK)

{
  "user": "8c88c0c0-1234-4abc-9def-0123456789ab",
  "from": "2026-08-01",
  "to": "2026-08-31",
  "unavailable": [
    { "from": "2026-08-10", "to": "2026-08-14" },
    { "from": "2026-08-24", "to": "2026-08-24" }
  ]
}

Ist der Mitarbeiter im gesamten Zeitraum durchgehend verfügbar, ist unavailable ein leeres Array.

Response-Felder

FeldTypBeschreibung
userstringDie angefragte UUID
from / tostringDer abgefragte Zeitraum (Bestätigung der Query-Parameter)
unavailablearrayListe zusammenhängender Zeiträume (from/to, jeweils Y-m-d), an denen der Mitarbeiter nicht verfügbar ist. Fasst genehmigten Urlaub, genehmigte sonstige Abwesenheiten und Zeitausgleich zusammen, ohne den Grund offenzulegen

Fehlerfälle

Benutzer nicht gefunden (404 Not Found):

{
  "error": "user_not_found",
  "message": "User with given UUID not found."
}

Kein Zugriff — Token gehört nicht diesem Mitarbeiter und ist kein Admin/TimeAdmin-Token (403 Forbidden):

{
  "error": "forbidden",
  "message": "Kein Zugriff auf Abwesenheiten dieses Mitarbeiters."
}

Fehlende Query-Parameter (400 Bad Request):

{
  "error": "missing_fields",
  "message": "Query-Parameter \"from\" und \"to\" (Y-m-d) sind erforderlich."
}

Ungültiges Datumsformat (400 Bad Request):

{
  "error": "invalid_date",
  "message": "Invalid date format, expected Y-m-d."
}

Zeitraum ungültig, to vor from (400 Bad Request):

{
  "error": "range_invalid",
  "message": "\"to\" muss nach \"from\" liegen."
}

Zeitraum zu groß, mehr als 366 Tage (400 Bad Request):

{
  "error": "range_too_large",
  "message": "Zeitraum darf maximal 366 Tage umfassen."
}

Beispiel-Request (cURL)

curl -X GET "https://ihre-domain.invoflux.de/ext-api/absences/8c88c0c0-1234-4abc-9def-0123456789ab?from=2026-08-01&to=2026-08-31" \
  -H "X-API-TOKEN: abc123def456..." \
  -H "Accept: application/json"

Fehlerbehandlung

HTTP-Statuscodes

CodeBedeutung
200 OKRequest erfolgreich
201 CreatedRessource erfolgreich angelegt (z.B. neue Reservierung)
400 Bad RequestUngültige Eingabedaten oder fehlende Pflichtfelder
401 UnauthorizedFehlende oder ungültige Authentifizierung
403 ForbiddenKeine Berechtigung für diese Aktion
404 Not FoundRessource (User, Projekt, Reservierung) nicht gefunden
409 ConflictAktion nicht möglich, da die Ressource sich bereits in einem finalen Zustand befindet (z.B. Storno einer bereits bestätigten Reservierung)

Fehlerformat

Alle Fehlermeldungen folgen diesem Format:

{
  "error": "error_code",
  "message": "Menschenlesbare Fehlerbeschreibung"
}

Benutzer-UUID (externalUuid)

Für die externe API wird empfohlen, Benutzer über eine UUID zu identifizieren statt über interne Datenbank-IDs.

UUID in der Datenbank anlegen

SQL-Migration:

ALTER TABLE user
    ADD COLUMN external_uuid VARCHAR(36) DEFAULT NULL,
    ADD UNIQUE INDEX UNIQ_USER_EXTERNAL_UUID (external_uuid);

UUID für Benutzer generieren

Beim Erstellen/Bearbeiten eines Benutzers:

use Symfony\Component\Uid\Uuid;

if (!$user->getExternalUuid()) {
    $user->setExternalUuid(Uuid::v4()->toRfc4122());
}

Die UUID kann dann in externen Systemen gespeichert und für API-Requests verwendet werden.


Sicherheitshinweise

  1. API-Token sicher aufbewahren: Tokens niemals in Versionskontrolle committen oder öffentlich zugänglich machen
  2. HTTPS verwenden: Alle API-Requests sollten über HTTPS erfolgen
  3. Token-Rotation: Regelmäßig neue Tokens generieren und alte widerrufen
  4. Minimale Berechtigungen: Nur Benutzern mit ROLE_MANAGER oder ROLE_ADMIN API-Token gewähren
  5. Rate Limiting: Bei massenhaftem Import externe Rate Limits beachten
  6. Base URL nicht hartkodieren: Jede InvoFlux-Installation hat eine eigene Domain — bei Integrationen, die mehrere Kunden bedienen, muss die Base URL Teil der Verbindungs-Konfiguration sein, nicht des Programmcodes

Beispiel-Workflow: Externes Zeiterfassungssystem

Szenario

Ein externes Terminal-System soll Arbeitszeiten an InvoFlux übermitteln.

Implementierung

1. Setup:

2. Täglicher Arbeitsbeginn:

curl -X POST https://ihre-domain.invoflux.de/ext-api/punch/work-start \
  -H "X-API-TOKEN: abc123..." \
  -d '{"workStatus":"OFFICE"}'

3. Status während des Tages abfragen:

curl -X GET https://ihre-domain.invoflux.de/ext-api/punch/status \
  -H "X-API-TOKEN: abc123..."

4. Arbeitsende:

curl -X POST https://ihre-domain.invoflux.de/ext-api/punch/work-end \
  -H "X-API-TOKEN: abc123..."

5. Nachträglicher Import (z.B. für vergessene Buchungen):

curl -X POST https://ihre-domain.invoflux.de/ext-api/punch/entry \
  -H "X-API-TOKEN: abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "user": "8c88c0c0-...",
    "date": "2026-01-27",
    "start": "09:00",
    "end": "17:00",
    "breakMinutes": 45,
    "reason": "Nachträglicher Import vom Terminal"
  }'

Beispiel-Workflow: Terminbuchungs-System (z.B. VQBooking)

Szenario

Ein Terminbuchungs-System soll Mitarbeiter für bestätigte Termine reservieren und kurzfristige Verfügbarkeit prüfen.

Implementierung

1. Setup pro Mitarbeiter/Kalenderverbindung:

2. Buchung bestätigt → Reservierung anlegen:

curl -X POST https://ihre-domain.invoflux.de/ext-api/reservations \
  -H "X-API-TOKEN: abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "user": "8c88c0c0-...",
    "date": "2026-07-10",
    "start": "10:00",
    "end": "12:00",
    "reason": "VQBooking: Kunde Müller GmbH – Beratungstermin",
    "externalRef": "vqbooking-booking-4711"
  }'

→ Reservierungs-id aus der Antwort speichern (mit der Buchung verknüpfen).

3. Buchung storniert/verschoben → Reservierung stornieren:

curl -X DELETE https://ihre-domain.invoflux.de/ext-api/reservations/42 \
  -H "X-API-TOKEN: abc123..."

Falls 409 already_confirmed zurückkommt: Der Mitarbeiter war zum Termin bereits als anwesend erkannt und die Zeit real gebucht — hier ist keine automatische Rücknahme mehr möglich.

4. Kurzfrist-Slot angefragt (z.B. minAdvanceHours = 0) → Verfügbarkeit live prüfen:

curl -X GET https://ihre-domain.invoflux.de/ext-api/punch/status/8c88c0c0-... \
  -H "X-API-TOKEN: abc123..."

→ Slot nur anzeigen, wenn available: true in der Antwort.

5. Terminkalender für die nächsten Wochen anzeigen → mehrtägig prüfen, an welchen Tagen der Mitarbeiter grundsätzlich ausfällt:

curl -X GET "https://ihre-domain.invoflux.de/ext-api/absences/8c88c0c0-...?from=2026-07-08&to=2026-08-08" \
  -H "X-API-TOKEN: abc123..."

→ Tage, die in unavailable auftauchen, im Kalender des Buchungssystems von vornherein nicht als buchbar anzeigen (ohne den Grund zu übernehmen/anzuzeigen).


Support

Bei Fragen zur API-Integration oder technischen Problemen:


Changelog

Version 2.1 (08.07.2026)

Version 2.0 (03.07.2026)

Version 1.0 (29.01.2026)