API-Verträge
DemoVertragsschicht zwischen neuem Frontend und bestehendem PHP-7.4-Backend. Basis /api/v1. Nur Beschreibung — keine Implementierung, keine Datenbankstruktur, keine echten IDs.
- Session ausschliesslich über HttpOnly-Cookie des PHP-Backends; kein Token im Storage oder in der URL.
- Jede schreibende Anfrage sendet den CSRF-Header X-Benson-Csrf mit dem Wert aus GET /session.
- Idempotenz über Header Idempotency-Key (UUID v4), Serverfenster 24 h, gleiche Antwort bei Wiederholung.
- Optimistische Sperre über If-Match/version — Konflikt ergibt 409 statt stillem Überschreiben.
- Autorisierung findet serverseitig statt; Capabilities steuern im Frontend nur die Sichtbarkeit.
- Antworten mit personenbezogenen Daten: Cache-Control: no-store.
- Fehlermeldungen bleiben generisch, keine Stacktraces und keine internen Pfade.
- Rate Limit je Session und Route; Überschreitung ergibt 429 mit Retry-After.
Erfolg
{ "data": <Nutzlast>, "meta": { "requestId": "req_demo_0001", "seite": 1, "proSeite": 25, "gesamt": 128 }, "error": null }Fehler
{ "data": null, "meta": { "requestId": "req_demo_0002" }, "error": { "code": "VALIDIERUNG", "message": "Eingabe unvollstaendig", "fields": { "telefon": "ungueltiges Format" } } }23 von 23 Verträgen
/api/v1/sessionLiefert Identität, Mandant, Arbeitsplatz und frischen CSRF-Wert nach Anmeldung oder Reload.
Request
keine Parameter
Response
benutzerId: stringopakes Kürzel, z. B. usr_demo_014anzeigename: stringmandantId: stringrollen: string[]csrfToken: stringnur im Body, nie in der URLablaufIso: string (ISO 8601)passwortWechselNoetig: boolean
Fehlerzustände
- Capability
- session.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag, nur technische Zugriffsmetrik
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 5000 ms — 1 Wiederholung bei Netzfehler, kein Retry bei 401
/api/v1/session/logoutBeendet die serverseitige Sitzung und invalidiert das Cookie.
Request
keine Parameter
Response
abgemeldet: boolean
Fehlerzustände
- Capability
- session.read
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- natürlich idempotent, wiederholter Aufruf liefert erneut abgemeldet=true
- Audit
- Pflicht: Benutzer, Zeit, Quell-IP-Hash
- Datenschutzklasse
- intern
- Timeout / Retry
- 5000 ms — keine automatische Wiederholung
/api/v1/capabilitiesLiefert die erlaubten Capabilities und die daraus abgeleitete Navigation für die Shell.
Request
keine Parameter
Response
capabilities: string[]Muster modul.objekt.aktionnavigation: { schluessel, titel, pfad, gruppe }[]merkmalsschalter: Record<string, boolean>
Fehlerzustände
- Capability
- session.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag
- Datenschutzklasse
- intern
- Timeout / Retry
- 5000 ms — 1 Wiederholung mit 500 ms Backoff
/api/v1/kunden?suche=&status=&seite=&proSeite=Serverseitig gefilterte, seitenweise Trefferliste für Backoffice und CRM.
Request
suche: stringmax. 120 Zeichen, serverseitig escapedstatus: enumneu | inArbeit | abgeschlossen | gesperrtseite: int>= 1proSeite: int10 | 25 | 50, Standard 25
Response
eintraege[].kundeId: stringeintraege[].name: stringeintraege[].telefonMaskiert: stringz. B. +49 30 •••• 42eintraege[].dncGesperrt: booleanmeta.gesamt: int
Fehlerzustände
- Capability
- crm.kunde.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- Suchzugriffe auf personenbezogene Daten protokollieren (Benutzer, Filter, Trefferzahl)
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 8000 ms — 1 Wiederholung nur bei Timeout
/api/v1/kunden/{kundeId}Stammdaten, DNC-Status, Historie und Notizen einer Akte.
Request
kundeId: string*opake ID, keine laufende Nummer
Response
kunde: Kundenobjektdnc: { gesperrt, quelle, gueltigBis }historie: Ereignis[]version: stringETag für optimistische Sperre
Fehlerzustände
- Capability
- crm.kunde.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- Pflicht: Akteneinsicht mit Benutzer, Kunde, Zeit
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 8000 ms — 1 Wiederholung nur bei Timeout
/api/v1/kunden/{kundeId}Teilaktualisierung der Stammdaten; DNC- und Sperrlogik bleibt im Backend.
Request
version: string*aus GET, sonst 409felder: Partial<Kunde>*Whitelist serverseitig
Response
kunde: Kundenobjektversion: string
Fehlerzustände
- Capability
- crm.kunde.update
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key + version; Wiederholung liefert denselben Stand
- Audit
- Pflicht: Feld-Diff ohne Klartext besonders schutzwürdiger Werte
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 10000 ms — kein automatischer Retry nach 4xx; bei Netzfehler Wiederholung mit gleichem Idempotency-Key
/api/v1/rueckrufeLegt einen Rückruftermin an; Zuweisung und Zeitfenster prüft das Backend.
Request
kundeId: string*faelligIso: string*Zukunft, max. 180 Tagenotiz: stringmax. 500 Zeichen, HTML wird verworfenpersoenlich: boolean
Response
rueckrufId: stringstatus: enum offen | erledigt | verfallen
Fehlerzustände
- Capability
- crm.rueckruf.create
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key verhindert Doppelanlage bei Doppelklick
- Audit
- Pflicht
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 10000 ms — 1 Wiederholung mit gleichem Idempotency-Key
/api/v1/produkte?kampagneId=Liefert freigegebene Produkte samt Preisen; Preisfindung bleibt Backendhoheit.
Request
kampagneId: string*
Response
produkte[].produktId: stringprodukte[].bezeichnung: stringprodukte[].preisCent: intprodukte[].steuersatz: decimal
Fehlerzustände
- Capability
- crm.produkt.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag
- Datenschutzklasse
- intern
- Timeout / Retry
- 8000 ms — 2 Wiederholungen mit Backoff (idempotent)
/api/v1/warenkorb/berechnungServer berechnet Summen, Rabatte und Steuer; das Frontend rechnet nie selbst verbindlich.
Request
kundeId: string*positionen[].produktId: string*positionen[].menge: int*1..99
Response
positionen: BerechnetePosition[]summeNettoCent: intsummeBruttoCent: intberechnungId: stringwird beim Auftrag referenziert
Fehlerzustände
- Capability
- crm.warenkorb.calc
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- reine Berechnung, wiederholbar; Ergebnis über berechnungId referenzierbar
- Audit
- kein Eintrag
- Datenschutzklasse
- intern
- Timeout / Retry
- 8000 ms — 1 Wiederholung bei Timeout
/api/v1/auftraegeLegt einen Auftrag aus einer serverseitig erzeugten Berechnung an.
Request
kundeId: string*berechnungId: string*max. 15 Minuten altdispositionCode: string*einwilligung: { art, zeitpunktIso }*
Response
auftragId: stringstatus: enum eingereicht | pruefung | bestaetigt | storniertversion: string
Fehlerzustände
- Capability
- auftrag.create
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key zwingend; Doppel-Submit liefert denselben auftragId
- Audit
- Pflicht: Einreichung, Benutzer, Kampagne, Betrag
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 15000 ms — nur Netzfehler, immer mit identischem Idempotency-Key
/api/v1/auftraege/{auftragId}/statusBackoffice bestätigt, bemängelt oder storniert einen Auftrag.
Request
version: string*neuerStatus: enum*nur erlaubte Übergänge, sonst 409begruendung: stringPflicht bei Storno
Response
status: stringversion: string
Fehlerzustände
- Capability
- auftrag.verify
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key + Statusübergangsprüfung
- Audit
- Pflicht: alter und neuer Status, Begründung, Benutzer
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 10000 ms — kein automatischer Retry
/api/v1/kampagnenKampagnenübersicht mit Listenzuordnung und Aktivstatus.
Request
keine Parameter
Response
kampagnen[].kampagneId: stringkampagnen[].bezeichnung: stringkampagnen[].aktiv: booleankampagnen[].listen: { listeId, bezeichnung, offen }[]
Fehlerzustände
- Capability
- kampagne.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag
- Datenschutzklasse
- intern
- Timeout / Retry
- 8000 ms — 2 Wiederholungen mit Backoff
/api/v1/listen/{listeId}/importNimmt eine CSV entgegen; Prüfung, DNC-Abgleich und Dublettenlogik laufen serverseitig.
Request
datei: multipart/form-data*nur text/csv, max. 10 MB, Inhaltsprüfungtrennzeichen: enum , | ;
Response
importId: stringstatus: enum angenommen | verarbeitung | fertig | fehlerhaftzeilenGesamt: intzeilenAbgelehnt: int
Fehlerzustände
- Capability
- kampagne.liste.import
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key + Prüfsumme der Datei verhindert Doppelimport
- Audit
- Pflicht: Dateiname, Prüfsumme, Zeilenbilanz, Benutzer
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 30000 ms — kein automatischer Retry, Status über GET /listen/importe/{importId}
/api/v1/mitarbeiter?aktiv=Übersicht über Konten, Rollen und Sperrzustände.
Request
aktiv: boolean
Response
mitarbeiter[].benutzerId: stringmitarbeiter[].anzeigename: stringmitarbeiter[].rollen: string[]mitarbeiter[].gesperrt: boolean
Fehlerzustände
- Capability
- admin.mitarbeiter.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- Pflicht: Zugriff auf Personalstammdaten
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 8000 ms — 1 Wiederholung bei Timeout
/api/v1/mitarbeiter/{benutzerId}/rollenSetzt die Rollenmenge eines Kontos; Rechte selbst bleiben serverseitig definiert.
Request
version: string*rollen: string[]*nur bekannte Rollen, Selbst-Entzug von admin verboten
Response
rollen: string[]version: string
Fehlerzustände
- Capability
- admin.rolle.assign
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- vollständige Ersetzung ist natürlich idempotent, zusätzlich Idempotency-Key
- Audit
- Pflicht: Rollen vorher/nachher, ausführender Benutzer
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 10000 ms — kein automatischer Retry
/api/v1/telefonie/agenten?kampagneId=Aktueller Status aller sichtbaren Agenten; Quelle ist der Backend-VICIdial-Adapter, nie das Frontend.
Request
kampagneId: string
Response
agenten[].agentId: stringagenten[].status: enum bereit | gespraech | nachbearbeitung | pause | offlineagenten[].seitSekunden: intagenten[].nummerMaskiert: stringnie vollständige RufnummerstandIso: stringfür Veraltet-Erkennung im Wallboard
Fehlerzustände
- Capability
- monitor.agent.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 4000 ms — Polling alle 5 s; kein Retry-Sturm, Backoff auf 15 s nach 3 Fehlern
/api/v1/telefonie/agenten/{agentId}/aktionMithören, Flüstern, Aufschalten oder Pause setzen — ausschliesslich über den Backend-Adapter.
Request
aktion: enum mithoeren | fluestern | aufschalten | pause | abmelden*begruendung: string*min. 5 Zeichen
Response
aktionId: stringergebnis: enum gestartet | abgelehnt
Fehlerzustände
- Capability
- monitor.supervisor.act
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key; gleiche Aktion innerhalb 10 s liefert dieselbe aktionId
- Audit
- Pflicht: Aktion, Ziel-Agent, Begründung, Zeit — revisionssicher
- Datenschutzklasse
- besonders schutzwuerdig
- Timeout / Retry
- 8000 ms — kein automatischer Retry
/api/v1/monitor/kennzahlen?zeitraum=heuteAggregierte Kennzahlen für Wallboard und Dashboard.
Request
zeitraum: enum heute | woche | monat
Response
gespraeche: intabschluesse: intumsatzCent: intwarteschlangen: { name, wartend, laengsteWartezeitSek }[]standIso: string
Fehlerzustände
- Capability
- monitor.kpi.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag
- Datenschutzklasse
- intern
- Timeout / Retry
- 6000 ms — Polling 10 s, Backoff bei Fehlern, letzter Stand bleibt sichtbar
/api/v1/portal/auftraege?status=&seite=Nur Aufträge des angemeldeten Mandanten; keine internen Kennzahlen oder Agentendaten.
Request
status: enum offen | inBearbeitung | abgeschlossenseite: int
Response
auftraege[].auftragId: stringauftraege[].bezeichnung: stringauftraege[].status: stringauftraege[].aktualisiertIso: string
Fehlerzustände
- Capability
- portal.auftrag.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- Pflicht: Mandant, Benutzer, Filter (Mandantentrennung nachweisbar)
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 8000 ms — 1 Wiederholung bei Timeout
/api/v1/portal/dokumente/{dokumentId}/ticketErzeugt ein kurzlebiges Ticket; der Download läuft danach als Stream über das Backend, nie über eine direkte Dateipfad-URL.
Request
dokumentId: string*opake ID, Mandantenbindung serverseitig
Response
ticket: stringeinmalig, gültig 60 sdownloadPfad: string/api/v1/portal/downloads/{ticket}
Fehlerzustände
- Capability
- portal.dokument.read
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- jedes Ticket ist einmalig; Wiederholung erzeugt neues Ticket
- Audit
- Pflicht: Dokument, Mandant, Benutzer, Zeit
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 8000 ms — kein automatischer Retry
/api/v1/chat/kanaele/{kanalId}/nachrichten?vor=&limit=Seitenweises Nachladen älterer Nachrichten; Kanalmitgliedschaft prüft das Backend.
Request
vor: stringCursor, keine laufende IDlimit: int1..100, Standard 50
Response
nachrichten[].nachrichtId: stringnachrichten[].autorId: stringnachrichten[].text: stringKlartext, Rendering ohne HTML-Interpretationnachrichten[].anhaenge: { anhangId, art, groesseBytes }[]naechsterCursor: string | null
Fehlerzustände
- Capability
- chat.kanal.read
- CSRF
- nicht erforderlich
- Idempotenz
- entfällt (lesend)
- Audit
- kein Eintrag
- Datenschutzklasse
- intern
- Timeout / Retry
- 6000 ms — 1 Wiederholung bei Timeout
/api/v1/chat/kanaele/{kanalId}/nachrichtenSendet Text und optional Referenzen auf bereits hochgeladene Anhänge.
Request
text: string*1..4000 Zeichen, HTML wird verworfenanhangIds: string[]max. 5, müssen dem Absender gehören
Response
nachrichtId: stringgesendetIso: string
Fehlerzustände
- Capability
- chat.nachricht.create
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key aus Client-Entwurfs-ID verhindert Doppelversand
- Audit
- kein Inhaltsprotokoll, nur Metadaten bei Moderationsfällen
- Datenschutzklasse
- intern
- Timeout / Retry
- 8000 ms — 1 Wiederholung mit gleichem Idempotency-Key
/api/v1/chat/anhaengeNimmt Datei oder Audio entgegen; Typprüfung, Grössenlimit und Virenscan serverseitig.
Request
datei: multipart/form-data*Whitelist: pdf, png, jpg, webm/opus; max. 25 MBart: enum datei | sprache*dauerSek: intnur bei Sprache, max. 300
Response
anhangId: stringabrufPfad: stringStream über Backend, kein Dateisystempfad
Fehlerzustände
- Capability
- chat.anhang.create
- CSRF
- erforderlich (X-Benson-Csrf)
- Idempotenz
- Idempotency-Key + Prüfsumme; identischer Upload liefert dieselbe anhangId
- Audit
- Pflicht: Uploader, Grösse, Typ, Scanergebnis
- Datenschutzklasse
- personenbezogen
- Timeout / Retry
- 30000 ms — kein automatischer Retry