API-Referenz
Basis-URL: https://api.saw-sg.de/v1
Auth: Authorization: Bearer {token} — alle Endpunkte außer /auth/register und /auth/login
Auth
POST /v1/auth/register
Neuen Account erstellen.
Body:
{ "name": "Max", "email": "max@example.com", "password": "geheim123", "password_confirmation": "geheim123" }Response 201:
{ "data": { "user": { "id": 1, "name": "Max", "email": "...", "role": "user", "plan": "free", "onboarding_completed": false }, "token": "1|abc..." } }POST /v1/auth/login
Anmelden und Token erhalten.
Body: { "email": "...", "password": "..." }
Response 200: Wie register
Response 401: { "error": "invalid_credentials", "message": "..." }
POST /v1/auth/logout 🔒
Token invalidieren. Response 200: { "message": "Erfolgreich abgemeldet." }
GET /v1/auth/me 🔒
Eingeloggten User laden. Response 200: { "data": { user } }
POST /v1/auth/onboarding/complete 🔒
Onboarding als abgeschlossen markieren. Response 200: { "message": "..." }
Templates
GET /v1/templates 🔒
Verfügbare Simulations-Vorlagen laden.
Response 200:
{ "data": [ { "id": 1, "name": "SaaS Startup", "industry": "Software / SaaS", "description": "...", "difficulty": "medium" } ] }Companies (Simulationen)
GET /v1/companies 🔒
Alle Simulationen des eingeloggten Users.
Response 200:
{
"data": [{
"id": 1, "name": "MeineSaaS", "industry": "...", "legal_form": "einzelunternehmen",
"status": "founding", "simulation_mode": "realistic",
"simulation_state": { "current_tick": 9, "simulated_date": "2026-06-30", "phase": "founding", "tick_speed": "day", "is_paused": false }
}]
}POST /v1/companies 🔒
Neue Simulation anlegen. Erstellt automatisch alle 1:1-Records (SimulationState, Bank, Institutionen etc.)
Body:
{
"name": "MeineSaaS GmbH",
"industry": "Software / SaaS",
"legal_form": "einzelunternehmen",
"simulation_mode": "realistic",
"template_id": 1,
"personal_expenses": 2500,
"side_income": 3000
}Response 201: { "data": { company } }
GET /v1/companies/{id} 🔒
Einzelne Simulation laden (inkl. SimulationState, Config, FounderFinance).
PATCH /v1/companies/{id} 🔒
Name, Simulationsmodus oder Tick-Speed ändern.
Body (alle optional): { "name": "...", "simulation_mode": "aggressive", "tick_speed": "week" }
DELETE /v1/companies/{id} 🔒
Simulation und alle zugehörigen Daten löschen.
Simulation Engine
GET /v1/companies/{id}/simulation/state 🔒
Aktuellen Simulationsstand laden.
Response 200:
{ "data": { "company_id": 1, "current_tick": 9, "simulated_date": "2026-06-30", "phase": "founding", "tick_speed": "day", "is_paused": false, "is_processing": false } }GET /v1/companies/{id}/simulation/dashboard 🔒
Dashboard-Daten: KPIs, Events, Kontostand, Kundenzahl.
Response 200:
{
"data": {
"company": { "id": 1, "name": "...", "status": "founding" },
"simulation": { "tick": 9, "simulated_date": "2026-06-30", "phase": "founding", "is_paused": false },
"kpi": { "revenue_monthly": 0, "expenses_monthly": 0, "profit_monthly": 0, "risk_index": 0, "stability_index": 50 },
"bank_balance": 0,
"customer_count": 0,
"recent_events": []
},
"meta": { "tick": 9, "simulated_date": "2026-06-30" }
}POST /v1/companies/{id}/simulation/tick 🔒
Simulation um 1 Tick (= 1 Tag) voranschreiten.
Response 200:
{ "data": { "tick": 10, "simulated_date": "2026-07-01", "phase": "founding", "events_count": 0, "month_changed": true, "is_paused": false } }POST /v1/companies/{id}/simulation/advance 🔒
Simulation um N Tage voranschreiten.
Body: { "days": 7 } (1–365)
Response 200: { "data": { "ticks_processed": 7, "last_tick": { ... } } }
POST /v1/companies/{id}/simulation/pause 🔒
Simulation pausieren.
POST /v1/companies/{id}/simulation/resume 🔒
Simulation fortsetzen.
Fehler-Format
{ "error": "invalid_credentials", "message": "E-Mail oder Passwort ist falsch.", "status": 401 }Validierungsfehler (422):
{ "message": "The name field is required.", "errors": { "name": ["The name field is required."] } }Mitarbeiter (Phase 4)
GET /v1/companies/{id}/employees 🔒
Alle Mitarbeiter. Status: probation, active, fired, resigned
GET /v1/companies/{id}/employees/candidates?role=support 🔒
3 Kandidaten-Vorschläge für eine Rolle (mit KI-Backstory wenn Claude konfiguriert).
POST /v1/companies/{id}/employees 🔒
Mitarbeiter einstellen. Body: { "name": "...", "role": "support", "archetype": "zuverlässiger", "salary_monthly": 2800 }
DELETE /v1/companies/{id}/employees/{id} 🔒
Mitarbeiter entlassen. Gibt 422 zurück wenn keine Abmahnung vorhanden (mit Risiko-Hinweis).
POST /v1/companies/{id}/employees/{id}/force-fire 🔒
Erzwungene Kündigung ohne Abmahnung (erhöht Risiko-Index, erzeugt critical Event).
KI-Coach (Phase 4)
Claude API
Coach-Antworten nutzen claude-sonnet wenn ANTHROPIC_API_KEY gesetzt ist. Ohne Key: regelbasierter Fallback (kein Fehler).
GET /v1/companies/{id}/coach 🔒
Coach-Gespräch laden (wird bei erstem Aufruf angelegt, KI-Begrüßung).
Response: { "data": { "messages": [...], "claude_active": true } }
POST /v1/companies/{id}/coach 🔒
Nachricht senden. Coach antwortet mit aktuellem Unternehmenskontext (Kontostand, Kunden, KPIs, offene Tasks).
Body: { "message": "Was sollte ich als nächstes tun?" }
DELETE /v1/companies/{id}/coach 🔒
Gespräch zurücksetzen.
Async Queue (Phase 4)
Ab 50 aktiven Kunden laufen Ticks asynchron:
Sync (< 50 Kunden): POST /tick → 200 OK { data: tickResult }
Async (≥ 50 Kunden): POST /tick → 202 Accepted { data: { async: true } } → Frontend pollt GET /simulation/state bis is_processing = false
n8n Webhook (Phase 4)
POST /api/v1/webhooks/n8n/tick-complete
X-Webhook-Secret: {N8N_WEBHOOK_SECRET}
{ "company_id": 1 }Setzt is_processing = false — wird von n8n nach abgeschlossenem Async-Job aufgerufen.
Bürokratie & Events (Phase 2)
GET /v1/companies/{id}/tasks 🔒
Aufgaben laden. Optional: ?status=pending|overdue|completed
Response 200:
{ "data": [{ "id": 1, "type": "impressum", "title": "Impressum erstellen", "status": "pending", "due_tick": 7, "penalty_amount": "1500.00", "sort_order": 4 }] }PATCH /v1/companies/{id}/tasks/{taskId}/complete 🔒
Aufgabe als erledigt markieren. Erzeugt automatisch ein Completion-Event.
GET /v1/companies/{id}/events 🔒
Ereignisse laden. Optional: ?severity=info|warning|critical, ?unread=true
PATCH /v1/companies/{id}/events/{eventId}/read 🔒
Event als gelesen markieren.
POST /v1/companies/{id}/events/read-all 🔒
Alle Events als gelesen markieren.
Institutionen (Phase 2)
GET /v1/companies/{id}/institutions 🔒
Alle 12 Institutionen mit Status und ungelesener Nachrichten-Anzahl.
Response 200:
{ "data": [{ "key": "hausbank", "name": "Hausbank", "is_active": true, "unread_count": 1 }] }GET /v1/companies/{id}/institutions/{institution}/messages 🔒
Alle Nachrichten einer Institution. Markiert sie automatisch als gelesen.
GET /v1/companies/{id}/institutions/{institution}/chat 🔒
Gesprächsverlauf laden (wird angelegt falls nicht vorhanden).
POST /v1/companies/{id}/institutions/{institution}/chat 🔒
Nachricht an Institution senden.
Body: { "message": "Wie hoch ist mein Kontostand?" }
Response 200: { "data": { "institution": "hausbank", "persona_name": "Thomas Weber", "messages": [...], "last_response": "..." } }
Bank (Phase 2)
GET /v1/companies/{id}/bank 🔒
Kontostand und letzte 20 Transaktionen.
POST /v1/companies/{id}/bank/deposit 🔒
Kapitaleinlage einzahlen (100–1.000.000 €).
Body: { "amount": 5000, "description": "Startkapital" }
Postamt (Phase 2)
GET /v1/companies/{id}/postamt/inbox 🔒
Alle eingehenden Behördenbriefe + Anzahl ungelesener Nachrichten.
GET /v1/companies/{id}/postamt/outbox 🔒
Alle versendeten Briefe mit Sendungsverfolgung.
POST /v1/companies/{id}/postamt/send 🔒
Brief an eine Behörde senden.
Body:
{ "recipient_institution": "finanzamt", "subject": "Anmeldung", "content": "...", "send_type": "einschreiben" }send_type: standard (0,85€, 2 Tage) · einschreiben (4,05€, 2 Tage) · einschreiben_rueckschein (6,45€, 3 Tage) · express (12,90€, 1 Tag)
GET /v1/companies/{id}/postamt/track/{tracking} 🔒
Sendungsverfolgung per Tracking-Nummer (z.B. VTABC12345).
GET /v1/companies/{id}/postamt/send-types 🔒
Alle verfügbaren Versandarten mit Kosten und Lieferzeit.
Rechtsdokumente (Phase 2)
GET /v1/companies/{id}/documents 🔒
Alle Pflichtdokumente (impressum, agb, datenschutz) mit Status.
Status: missing → draft → submitted → approved
PATCH /v1/companies/{id}/documents/{type} 🔒
Dokument-Status aktualisieren. Schließt automatisch den zugehörigen Task ab.
Body: { "status": "approved", "content": "Impressum gemäß §5 TMG..." }
type: impressum · agb · datenschutz