Public API - Übersicht Admin

📕 Für Administratoren und Entwickler - Diese Dokumentation beschreibt die spiritflow Public API für die programmatische Integration mit externen Systemen.

Überblick

Die spiritflow Public API ermöglicht die programmatische Integration von Aufgaben, Kunden, Projekten, Rechnungen und weiteren Ressourcen in externe Systeme. Die API ist REST-basiert und gibt JSON-Antworten zurück.

Basis-URL:

https://app.spiritflow.team/api/v1

Datumsformat: Alle Zeitstempel werden im ISO 8601-Format in UTC zurückgegeben (Beispiel: 2025-03-01T10:30:00Z). Datumsfelder ohne Uhrzeit (z.B. dueDate bei Projekten) werden als YYYY-MM-DD dargestellt.

Mandantenisolation: Jeder API-Key ist an genau einen Mandanten gebunden. Anfragen werden automatisch auf die Daten des jeweiligen Mandanten beschränkt. Es ist nicht möglich, über die API auf Daten eines anderen Mandanten zuzugreifen.


Authentifizierung

Die Public API authentifiziert alle Anfragen über einen API-Key, der als HTTP-Header übermittelt wird.

Header-Format

X-API-Key: sf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API-Key erstellen

API-Keys werden in der spiritflow-Anwendung unter Einstellungen > Integrationen > API-Keys erstellt. Nur Tenant-Administratoren können API-Keys erstellen und verwalten.

Pro Mandant sind maximal 10 API-Keys zulässig.

Sicherheitshinweis: Der vollständige API-Key wird nur einmalig bei der Erstellung angezeigt. Bewahren Sie ihn sicher auf. Es ist nicht möglich, den Schlüssel später erneut einzusehen.

Fehler bei Authentifizierung

SituationHTTP-StatusFehlercode
API-Key fehlt oder leer401UNAUTHORIZED
API-Key ungültig oder widerrufen401INVALID_API_KEY
API-Key abgelaufen401API_KEY_EXPIRED
IP-Adresse nicht erlaubt403IP_NOT_ALLOWED
Scope fehlt403ACCESS_DENIED

Response-Format

Alle Antworten folgen einem einheitlichen Hullformat.

Erfolg - Einzelobjekt

{
  "data": {
    "id": 42,
    "title": "Webseite für Firma XYZ erstellen",
    "status": "IN_PROGRESS"
  },
  "meta": {
    "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "timestamp": "2025-03-01T10:30:00Z"
  }
}

Erfolg - Liste mit Pagination

{
  "data": [
    {
      "id": 42,
      "title": "Webseite für Firma XYZ erstellen",
      "status": "IN_PROGRESS"
    },
    {
      "id": 43,
      "title": "Logo-Design überarbeiten",
      "status": "PLANNED"
    }
  ],
  "pagination": {
    "page": 0,
    "size": 20,
    "totalElements": 57,
    "totalPages": 3
  },
  "meta": {
    "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "timestamp": "2025-03-01T10:30:00Z"
  }
}

Fehler

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Task with ID 999 not found for this tenant.",
    "status": 404,
    "details": {
      "id": 999
    }
  },
  "meta": {
    "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "timestamp": "2025-03-01T10:30:00Z"
  }
}

Pagination

Alle Listen-Endpunkte unterstützen Pagination über Query-Parameter:

ParameterTypStandardBeschreibung
pageInteger0Seitennummer (0-basiert)
sizeInteger20Einträge pro Seite (max. 100)
sortStringabhaengig vom EndpunktSortierfeld und Richtung, Format: feld,richtung

Beispiele für sort:

  • createdAt,desc - Neueste zuerst
  • title,asc - Alphabetisch aufsteigend
  • dueDate,asc - Fruehestes Fälligkeitsdatum zuerst

Scopes

Jeder API-Key trägt eine oder mehrere Berechtigungen (Scopes). Die verfügbaren Scopes sind:

ScopeBeschreibungErlaubte Operationen
tasks:readAufgaben lesenGET-Anfragen auf /api/v1/tasks
tasks:writeAufgaben schreibenPOST, PUT, PATCH, DELETE auf /api/v1/tasks
customers:readKunden lesenGET-Anfragen auf /api/v1/customers
customers:writeKunden schreibenPOST, PUT, DELETE auf /api/v1/customers
projects:readProjekte lesenGET-Anfragen auf /api/v1/projects
projects:writeProjekte schreibenPOST, PUT, DELETE auf /api/v1/projects
invoices:readRechnungen lesenGET-Anfragen auf /api/v1/invoices (nur lesend)
interactions:readInteraktionen lesenGET-Anfragen auf /api/v1/customers/{id}/interactions
interactions:writeInteraktionen schreibenPOST auf /api/v1/customers/{id}/interactions
cti:readCTI-Daten lesenGET-Anfragen auf /api/v1/cti/lookup und /api/v1/cti/device-mappings
cti:writeCTI-Events sendenPOST auf /api/v1/cti/events/incoming-call
users:readBenutzer lesenGET-Anfragen auf /api/v1/users
users:writeBenutzer anlegenPOST auf /api/v1/users, POST auf /api/v1/users/{id}/avatar
time_entries:readZeiteinträge lesenGET-Anfragen auf /api/v1/time-entries
time_entries:writeZeiteinträge schreibenPOST, PUT, DELETE auf /api/v1/time-entries
vacation:readUrlaubsanträge lesenGET-Anfragen auf /api/v1/vacation-requests
vacation:writeUrlaubsanträge erstellenPOST auf /api/v1/vacation-requests
sick_leave:readKrankmeldungen lesenGET-Anfragen auf /api/v1/sick-leaves
sick_leave:writeKrankmeldungen erstellenPOST auf /api/v1/sick-leaves
tags:readTags lesenGET-Anfragen auf /api/v1/tags
tags:writeTags erstellenPOST auf /api/v1/tags
receipts:readBelege lesenGET-Anfragen auf /api/v1/receipts
receipts:writeBelege erstellen und bearbeitenPOST, PATCH auf /api/v1/receipts
webhooks:readWebhooks lesenGET-Anfragen auf /api/v1/webhooks
webhooks:writeWebhooks verwaltenPOST, PUT, DELETE auf /api/v1/webhooks
tenant:readMandantendaten lesenGET-Anfragen auf /api/v1/tenant
tenant:writeMandantendaten ändernPUT-Anfragen auf /api/v1/tenant

DSGVO-Hinweis: Die CTI-Scopes (cti:read, cti:write) ermöglichen den Zugriff auf Kundendaten (Telefonnummern, Namen) durch externe Systeme. Stellen Sie sicher, dass die CTI-Middleware in Ihrem Auftragsverarbeitungsvertrag (AVV) abgedeckt ist.

DSGVO-Hinweis: Krankmeldungen (sick_leave:read, sick_leave:write) sind Gesundheitsdaten und unterliegen besonderem Schutz gemäß DSGVO. Dieser Scope ist bewusst vom Urlaubs-Scope getrennt und sollte nur für Systeme vergeben werden, die diese Daten zwingend benötigen.

Hinweis: tasks:write schließt NICHT automatisch tasks:read ein. Für vollständigen Zugriff benötigen Sie beide Scopes. Gleiches gilt für alle anderen Ressourcen mit getrennten Lese- und Schreib-Scopes.

Sonderregel: Der Endpunkt GET /api/v1/projects/{id}/tasks erfordert sowohl projects:read als auch tasks:read.


Fehler-Codes

Alle Fehlermeldungen werden im einheitlichen Fehlerformat zurückgegeben (siehe Response-Format).

HTTP-StatusCodeBeschreibung
400VALIDATION_ERROREingabefehler: Pflichtfeld fehlt, Wert ungültig oder Längenbeschraenkung überschritten
400BAD_REQUESTAllgemeiner Fehler in der Anfrage
401UNAUTHORIZEDAPI-Key fehlt
401INVALID_API_KEYAPI-Key ungültig oder widerrufen
401API_KEY_EXPIREDAPI-Key ist abgelaufen
403IP_NOT_ALLOWEDIP-Adresse des Aufrufers ist nicht in der Whitelist des API-Keys
403ACCESS_DENIEDAPI-Key hat nicht den erforderlichen Scope für diese Operation
404NOT_FOUNDRessource nicht gefunden oder nicht zu diesem Mandanten gehoerig
409CONFLICTKonflikt mit aktuellem Zustand der Ressource (z.B. Überlappung bei Urlaubsanträgen)
422VIRUS_DETECTEDHochgeladene Datei wurde als infiziert erkannt und abgelehnt
429RATE_LIMIT_EXCEEDEDRate Limit überschritten
500INTERNAL_ERRORInterner Serverfehler
503VIRUS_SCAN_FAILEDVirenscanner ist derzeit nicht verfügbar
503VIRUS_SCAN_TIMEOUTVirenscanner hat nicht rechtzeitig geantwortet

Rate Limiting

Die Public API begrenzt die Anzahl der Anfragen pro API-Key.

Limit: 1.000 Anfragen pro Minute pro API-Key

Response-Header

Bei jeder Antwort werden folgende Header mitgeliefert:

HeaderBeschreibung
X-RateLimit-LimitMaximale Anfragen pro Minute
X-RateLimit-RemainingVerbleibende Anfragen im aktuellen Zeitfenster
X-RateLimit-ResetUnix-Timestamp, wann das Zeitfenster zurückgesetzt wird

Antwort bei Rate Limit Überschreitung

Wenn das Rate Limit überschritten wird, antwortet der Server mit HTTP 429 Too Many Requests:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. You have sent too many requests. Please wait before retrying.",
    "status": 429,
    "details": {
      "retryAfterSeconds": 30
    }
  },
  "meta": {
    "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "timestamp": "2025-03-01T10:30:00Z"
  }
}

Empfehlung: Implementieren Sie Exponential Backoff in Ihrer Anwendung, um bei einem 429-Fehler nicht sofort erneut anzufragen. Warten Sie nach dem ersten Fehler z.B. 1 Sekunde, nach dem zweiten 2 Sekunden, nach dem dritten 4 Sekunden usw. Der retryAfterSeconds-Wert in der Fehlerantwort gibt an, nach wie vielen Sekunden das Rate Limit zurückgesetzt wird.