Vigotime Planner API
Integriere die Dienstplanung headless: Du schickst einen self-contained Payload (Mitarbeiter, Schichten, Regeln, Abwesenheiten) — und bekommst einen fertigen Dienstplan zurück. Kein Wissen über die interne Datenhaltung nötig, kein Zwang zu unserer Oberfläche.
Überblick
Drei Endpoints, asynchron: absenden → Status pollen → Ergebnis holen.
Self-contained
Alle Entitäten reisen im Request mit — keine Vor-Synchronisation, kein Datenbankzugriff bei uns.
Asynchron
Der Solver läuft im Hintergrund; du pollst den Job-Status und holst das Ergebnis.
Pro Paket limitiert
Problemgröße, Solver-Zeit, Rate-Limit und Parallelität sind je Tarif konfiguriert.
Basis-URLs
| Umgebung | Basis-URL |
|---|---|
| Production | https://planner.vigotime.com |
| Staging | https://staging-planner.vigotime.com |
| Lokal (dev) | http://localhost:8000 |
Authentifizierung
Einer der beiden Header genügt. Der API-Key bestimmt zugleich den Tarif und damit die Limits.
# API-Key (für Drittanbieter)
X-API-Key: <dein-api-key>
# oder Firebase-Bearer (interne Nutzung)
Authorization: Bearer <firebase-id-token>
Quickstart
Job absenden, Status pollen, Ergebnis holen — mit curl und jq.
BASE=https://staging-planner.vigotime.com
KEY=<dein-api-key>
# 1) Job absenden
JOB=$(curl -s -X POST "$BASE/api/v1/solve" \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{
"start_date": "2026-07-01",
"end_date": "2026-07-07",
"department": { "id": "d1", "name": "Pflege Station 1" },
"employees": [
{ "id": "e1", "primaryDepartmentId": "d1", "contractHoursPerWeek": 40, "qualificationIds": ["q_exam"] }
],
"shifts": [
{ "id": "s_frueh", "departmentId": "d1", "name": "Frühdienst",
"startTime": "06:00", "endTime": "14:00", "shiftType": "early", "minStaff": 1 }
],
"config": { "timeout_seconds": 30 }
}' | jq -r .job_id)
# 2) Status pollen
curl -s "$BASE/api/v1/solve/$JOB" -H "X-API-Key: $KEY" | jq .status
# 3) Ergebnis holen
curl -s "$BASE/api/v1/solve/$JOB/result" -H "X-API-Key: $KEY" | jq .
Beispiel-Antwort des Ergebnisses:
{
"success": true,
"status": "optimal",
"assignments": [
{ "employee_id": "e1", "shift_id": "s_frueh", "date": "2026-07-01" }
],
"unassigned_shifts": [],
"execution_time_seconds": 0.8
}
Konzepte
Payload-Form
Mitarbeiter, Schichten und Abteilung werden in der Firestore-Dokument-Form (camelCase)
übergeben — dieselbe Form, die unser System intern nutzt. Pflichtfeld je Entität ist id;
alles Weitere hat sinnvolle Defaults. Daten-Maps wie wishes, vacations oder
sick_leaves haben die Form { "employeeId": ["2026-07-03", …] }.
Asynchrones Job-Modell
POST /solve liefert sofort 202 mit einer job_id und dem aufgelösten
tier. Pollen über GET /solve/{job_id} bis status =
completed (oder failed); dann /result abrufen.
Status-Werte
| Job-Status | Solver-Status (im Ergebnis) |
|---|---|
pending, running, completed, failed |
optimal, feasible, infeasible, unknown, model_invalid |
Limits pro Tarif
Der API-Key wird einem Tarif zugeordnet; dieser bestimmt die Grenzen. Die Solver-Laufzeit
wird serverseitig hart gedeckelt (min(config.timeout_seconds, Tarif-Cap)).
| Tarif | max. Problemgröße (MA × Tage × Schichten) | Solver-Zeit | Req/min | parallel |
|---|---|---|---|---|
free | 840 | 15 s | 10 | 1 |
standard | 15 500 | 30 s | 30 | 3 |
pro | 99 200 | 60 s | 60 | 8 |
enterprise | ∞ | 120 s | ∞ | 20 |
422
bevor der Solver startet. Bei Überschreiten des Rate-Limits kommt 429 mit
Retry-After.Fehler
| Code | Bedeutung |
|---|---|
401 | Keine/ungültige Authentifizierung |
422 | Problemgröße über dem Tarif-Limit |
429 | Rate-Limit des Tarifs überschritten |
404 | Job nicht gefunden |
400 | Ergebnis abgerufen, obwohl Job noch nicht fertig |
Fehlerformat: { "detail": "…" } bzw. { "error": { "code", "message" } }.
Vollständige API-Referenz
Alle Felder, Schemas und Beispiele interaktiv: