API - Zeiterfassung & Urlaub Admin
📕 Für Administratoren und Entwickler.
Die Zeiterfassungs-API erlaubt den vollständigen Zugriff auf Zeiteinträge sowie das Verwalten von Urlaubsantraegen und Krankmeldungen. Zeiteinträge können gelesen, erstellt, aktualisiert und gelöscht werden. Für Urlaubsantraege und Krankmeldungen stehen Lese- und Erstellendpunkte bereit.
Zeiteinträge (Time Entries)
Basis-Pfad: /api/v1/time-entries
Zeiteinträge auflisten
GET /api/v1/time-entries
Scope: time_entries:read
Query-Parameter
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
userId | Long | Nein | – | Nach Benutzer filtern |
projectId | Long | Nein | – | Nach Projekt filtern |
startDate | String | Nein | – | Startdatum (YYYY-MM-DD) |
endDate | String | Nein | – | Enddatum (YYYY-MM-DD) |
page | Integer | Nein | 0 | Seitennummer (0-basiert) |
size | Integer | Nein | 50 | Einträge pro Seite (max. 100) |
Antwort-Felder
| Feld | Typ | Beschreibung |
|---|---|---|
id | number | Eindeutige ID |
userId | number | ID des Benutzers |
userDisplayName | string | Anzeigename des Benutzers |
projectId | number oder null | ID des Projekts (null bei allgemeinen Aufgaben) |
projectName | string oder null | Name des Projekts |
taskId | number oder null | ID der verknuepften Aufgabe |
taskTitle | string oder null | Titel der verknuepften Aufgabe |
date | string | Datum des Eintrags (YYYY-MM-DD) |
startTime | string oder null | Startzeit (HH:mm) |
endTime | string oder null | Endzeit (HH:mm) |
durationMinutes | number | Dauer in Minuten |
durationHours | number | Dauer in Dezimalstunden |
description | string oder null | Beschreibung |
billable | boolean | Abrechenbar |
billed | boolean | Bereits abgerechnet |
hourlyRate | number oder null | Stundensatz zum Zeitpunkt des Eintrags |
revenue | number oder null | Berechneter Umsatz |
approvalStatus | string | PENDING, APPROVED oder REJECTED |
entryType | string | WORK, TRAVEL, BREAK oder FLAT_FEE |
externalReference | string oder null | Externe Referenz (z.B. ERP-Nummer) |
archived | boolean | Archiviert (gelöscht) |
createdAt | string | Erstellungszeitpunkt (ISO 8601, UTC) |
updatedAt | string | Letzter Aenderungszeitpunkt (ISO 8601, UTC) |
cURL-Beispiel
curl "https://app.spiritflow.team/api/v1/time-entries?startDate=2025-03-01&endDate=2025-03-31&projectId=5" \
-H "X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Einzelnen Zeiteintrag abrufen
GET /api/v1/time-entries/{id}
Scope: time_entries:read
Pfad-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
id | Long | ID des Zeiteintrags |
Antwort (200 OK)
Einzelnes Zeiteintrag-Objekt mit gleicher Struktur wie in der Liste.
cURL-Beispiel
curl "https://app.spiritflow.team/api/v1/time-entries/1042" \
-H "X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Zeiteintrag erstellen
POST /api/v1/time-entries
Scope: time_entries:write
Request-Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
userId | number | Ja | ID des Benutzers |
projectId | number | Nein | ID des Projekts |
taskId | number | Nein | ID der Aufgabe |
date | string | Ja | Datum (YYYY-MM-DD) |
startTime | string | Nein | Startzeit (HH:mm) |
endTime | string | Nein | Endzeit (HH:mm) |
durationMinutes | number | Nein | Dauer in Minuten (min. 1) |
description | string | Nein | Beschreibung (max. 2000 Zeichen) |
billable | boolean | Nein | Abrechenbar (Standard: true) |
entryType | string | Nein | WORK (Standard), TRAVEL, BREAK oder FLAT_FEE |
externalReference | string | Nein | Externe Referenz (max. 255 Zeichen) |
Hinweis: Entweder
durationMinutesoderstartTime+endTimemüssen angegeben werden. Bei Angabe von Start- und Endzeit wird die Dauer automatisch berechnet.
Antwort (201 Created)
Gleiche Felder wie bei der Zeiteintragsliste.
cURL-Beispiel
curl -X POST "https://app.spiritflow.team/api/v1/time-entries" \
-H "X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"userId": 2,
"projectId": 5,
"taskId": 42,
"date": "2025-03-15",
"durationMinutes": 120,
"description": "Frontend-Entwicklung: Kontaktformular",
"billable": true
}'
Zeiteintrag aktualisieren
PUT /api/v1/time-entries/{id}
Scope: time_entries:write
Alle Felder sind optional — nur die angegebenen Felder werden geändert. Die Struktur des Request-Bodys entspricht dem Erstell-Endpunkt.
Hinweis: Bereits abgerechnete Zeiteinträge (
billed: true) können nicht mehr geändert werden.
Pfad-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
id | Long | ID des Zeiteintrags |
Antwort (200 OK)
Aktualisiertes Zeiteintrag-Objekt.
Zeiteintrag löschen (archivieren)
DELETE /api/v1/time-entries/{id}
Scope: time_entries:write
Pfad-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
id | Long | ID des Zeiteintrags |
Antwort
204 No Content
Hinweis: Bereits abgerechnete Zeiteinträge können nicht gelöscht werden.
Urlaub (Vacation Requests)
Basis-Pfad: /api/v1/vacation-requests
Urlaubsantraege umfassen regulaeren Urlaub, Sonderurlaub und unbezahlten Urlaub. Krankmeldungen werden über einen separaten Endpunkt verwaltet und erscheinen nicht in dieser Liste.
Status-Werte für Urlaubsantraege
| Status | Bedeutung |
|---|---|
PENDING | Ausstehend, noch nicht entschieden |
APPROVED | Genehmigt |
REJECTED | Abgelehnt |
CANCELLED | Storniert |
Urlaubsantraege auflisten
GET /api/v1/vacation-requests
Scope: vacation:read
Query-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
status | string | Nein | Filter: PENDING, APPROVED, REJECTED oder CANCELLED |
ownerId | Long | Nein | Nach Benutzer filtern |
Antwort-Felder
| Feld | Typ | Beschreibung |
|---|---|---|
id | number | Eindeutige ID |
title | string | Titel des Antrags |
type | string | VACATION, SPECIAL_LEAVE oder UNPAID_LEAVE |
status | string | Aktueller Status |
ownerId | number | ID des Antragstellers |
ownerName | string | Name des Antragstellers |
startDate | string | Startdatum (YYYY-MM-DD) |
endDate | string | Enddatum (YYYY-MM-DD) |
daysCount | number | Anzahl der Urlaubstage |
reason | string oder null | Begruendung |
createdAt | string | Erstellungszeitpunkt (ISO 8601, UTC) |
updatedAt | string | Letzter Aenderungszeitpunkt (ISO 8601, UTC) |
Hinweis: Krankmeldungen (
SICK) werden nicht über diesen Endpunkt zurückgegeben — dafür den separaten Endpunkt/api/v1/sick-leavesverwenden.
Urlaubsantrag erstellen
POST /api/v1/vacation-requests
Scope: vacation:write
Request-Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ownerId | number | Ja | ID des Benutzers |
type | string | Nein | VACATION (Standard), SPECIAL_LEAVE oder UNPAID_LEAVE |
startDate | string | Ja | Startdatum (YYYY-MM-DD) |
endDate | string | Ja | Enddatum (YYYY-MM-DD) |
reason | string | Nein | Begruendung |
title | string | Nein | Titel (wird automatisch generiert, falls leer) |
autoApprove | boolean | Nein | Automatisch genehmigen (Standard: false) |
Fehler-Codes
| HTTP-Status | Code | Beschreibung |
|---|---|---|
| 409 | CONFLICT | Überlappung mit bereits genehmigtem Urlaub |
cURL-Beispiel
curl -X POST "https://app.spiritflow.team/api/v1/vacation-requests" \
-H "X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"ownerId": 5,
"startDate": "2025-07-14",
"endDate": "2025-07-25",
"reason": "Sommerurlaub"
}'
Krankmeldungen (Sick Leaves)
Basis-Pfad: /api/v1/sick-leaves
DSGVO-Hinweis: Krankmeldungen sind Gesundheitsdaten und unterliegen besonderem Datenschutz gemäß Art. 9 DSGVO. Der Zugriff erfordert separate Scopes (
sick_leave:read/sick_leave:write), die unabhängig vom Urlaubs-Scope vergeben werden. Vergeben Sie diese Scopes nur an API-Keys, die sie wirklich benötigen.
Krankmeldungen auflisten
GET /api/v1/sick-leaves
Scope: sick_leave:read
Query-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ownerId | Long | Nein | Nach Benutzer filtern |
Antwort
Gleiche Felder wie bei Urlaubsantraegen, jedoch mit type: "SICK".
cURL-Beispiel
curl "https://app.spiritflow.team/api/v1/sick-leaves?ownerId=5" \
-H "X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Krankmeldung erstellen
POST /api/v1/sick-leaves
Scope: sick_leave:write
Request-Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ownerId | number | Ja | ID des Benutzers |
startDate | string | Ja | Erster Krankheitstag (YYYY-MM-DD) |
endDate | string | Ja | Letzter Krankheitstag (YYYY-MM-DD) |
reason | string | Nein | Optionaler Hinweis |
Besonderes Verhalten
- Krankmeldungen werden automatisch genehmigt (Status direkt
APPROVED) - Bereits genehmigte Urlaubsantraege, die sich mit dem Krankmeldungszeitraum überschneiden, werden automatisch storniert
Antwort (201 Created)
Krankmeldungs-Objekt mit gleicher Struktur wie bei Urlaubsantraegen (mit type: "SICK").
cURL-Beispiel
curl -X POST "https://app.spiritflow.team/api/v1/sick-leaves" \
-H "X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"ownerId": 5,
"startDate": "2025-03-10",
"endDate": "2025-03-12"
}'