Eviworx
Docs

Approvals API

Approvals bündelt alle Genehmigungen und Bestätigungen des Systems in zwei Teilen: (1) EntityApproval — persistierte Multi-Approver-Records mit konfigurierbaren Strategien (ALL, ANY, MAJORITY, QUORUM), Approval-Groups und -Configs, für Changes, Change-Templates, Incidents (Closure/Data-Breach) und Workflow-Genehmigungsschritte; (2) die Union-Inbox (GET /api/approvals/inbox), die offene Entscheidungen aus mehreren Bereichen in einer Liste zusammenführt (Abwesenheiten, Asset-Übergaben, Change-Task-Freigaben u. a.).

Funktionen
✓ Ein Genehmigungssystem für 4 Entity-Types
✓ 4 Strategien (ALL, ANY, MAJORITY, QUORUM)
✓ Wiederverwendbare Approval-Groups
✓ Approval-Configs pro Entity-Type
✓ Auto-Approval (nach Feld, Recht oder Rolle)
✓ Kein Selbst-Genehmigen durch den Antragsteller
✓ Verhalten bei Ablehnung einstellbar (failOnReject)
✓ Frist für Workflow-Genehmigungsschritte (dueTimeAmount/dueTimeUnit)
✓ Automatischer Status-Sync der Entität
✓ Audit-Trail jeder Entscheidung (+ Activity-Log)

Unterstützte Entity-Types

Entity-Type Beschreibung Status-Auswirkung
CHANGE Change-Genehmigung (Multi-Approver) → APPROVED / REJECTED
INCIDENT Incident-Abschluss und -Wiedereröffnung (inkl. DSGVO Data-Breach) → CLOSED / RESOLVED
CHANGE_TEMPLATE Change-Template-Genehmigung → APPROVED / REJECTED
WORKFLOW Genehmigungs-Schritte laufender Workflows (Approver-Recht: workflows.completeSteps) → Schritt APPROVED / REJECTED

Genehmigungsschritte in Workflows können automatisch entschieden werden: Auto-Approve- und Auto-Reject-Bedingungen prüfen einen Feldwert der Workflow-Daten, ein Recht oder eine Rolle; mehrere Bedingungen werden mit UND oder ODER verknüpft. Auto-Reject wird vor Auto-Approve geprüft. Eine Frist erhält der Schritt über Menge und Einheit (dueTimeAmount, dueTimeUnit); daraus ergibt sich das Fälligkeitsdatum der Genehmigung. Von Hand entschieden wird ein solcher Schritt über den Approve-Endpoint der Instanz (APPROVED oder REJECTED, dazu ein optionaler Kommentar); abschließen lässt er sich nicht. So nimmt jede Entscheidung denselben Weg — mit derselben Rechteprüfung, demselben Protokoll und demselben Verhalten bei Ablehnung. Der Kommentar erscheint anschließend im Vorgang unter den Schritt-Ausgaben. Konfiguration und Beispiele: Workflows API →

Cross-Domain Pending-Inbox (Union-Inbox)

Über die EntityApproval-Records hinaus sammelt die Union-Inbox (GET /api/approvals/inbox) offene Entscheidungen aus mehreren Domains zu einer einheitlichen Liste. Jede Quelle liefert nur Einträge, die der Aufrufer sehen darf; fehlt das Recht für eine Quelle, bleibt sie leer (kein 403). Zugewiesene ARBEIT (Tickets, Incidents, Probleme, Changes, Change-Tasks, Workflow-Schritte) ist davon getrennt und läuft über /api/my-tasks.

ProviderQuelle
entityApprovalEntityApproval-Records (Change/Incident/Template)
absenceAbwesenheits-Anträge (Manager-Entscheidung)
handoverAsset-Handover-Bestätigungen
changeTaskReadyChange-Task „ready"-Bestätigungen
cascadingAwarenessCascading-Awareness-Hinweise

Endpoints Übersicht

Approvals (User-Facing)

Method Endpoint Beschreibung
GET/api/my-tasksZugewiesene Arbeits-Items (keine Entscheidungen) — dokumentiert in der API-Übersicht
GET/api/my-tasks/countAnzahl zugewiesener Arbeits-Items je Scope (für Badges)
GET/api/approvals/inboxUnion-Inbox der offenen Approvals über alle Quellen (?types= CSV, ?limit 1–200 [Default 50], ?offset)
GET/api/approvals/inbox/countZähler je Quelle (Badge/Tabs)
POST/api/approvals/inbox/decideUniversal-Entscheidung über die Inbox-ID (TYPE:id)
GET/api/approvals/checkPrüft, ob ein entityType/subType ein Approval erfordert (Konfigurationsdaten für Erstell- und Schließen-Dialoge)
POST/api/approvals/:id/decideEntscheidung treffen (Approve/Reject)

Die Union-Inbox hat keine eigene Berechtigung. Jede Quelle prüft ihre Rechte selbst, damit auch Endanwender ihre Bestätigungs-Aufgaben sehen. Wer für keine Quelle berechtigt ist, erhält eine leere Liste. Ungültige Eingaben lehnt die API mit 400 ab: ein unbekannter types-Wert sowie ein nicht-numerisches limit oder ein limit außerhalb 1–200. Ebenso verlangt /check einen gültigen entityType.

Approver und Kommentare einer Entität kommen aus deren eigenem Detail-Payload (Change, Incident, Problem) — dort gelten die Sichtrechte der jeweiligen Entität.

Approval Groups (Admin)

Method Endpoint Beschreibung
GET/api/admin/approval-groupsAlle Approval-Groups
POST/api/admin/approval-groupsNeue Approval-Group erstellen
PATCH/api/admin/approval-groups/:idGroup aktualisieren (partiell)
DELETE/api/admin/approval-groups/:idGroup löschen
GET/api/admin/approval-groups/:id/membersGroup-Mitglieder
GET/api/admin/approval-groups/:id/eligible-membersPotentielle Mitglieder (noch nicht in Group) — ?search=, ?take/skip; liefert {data, total}
POST/api/admin/approval-groups/:id/membersMitglied hinzufügen
PATCH/api/admin/approval-groups/:id/members/:memberIdMitglied aktualisieren (z.B. required-Flag)
DELETE/api/admin/approval-groups/:id/members/:memberIdMitglied entfernen (memberId = Entry-ID)

Approval Configs (Admin)

Method Endpoint Beschreibung
GET/api/admin/approval-configsAlle Approval-Konfigurationen
GET/api/admin/approval-configs/:idConfig Details
POST/api/admin/approval-configsNeue Config erstellen
PUT/api/admin/approval-configs/:idConfig aktualisieren
DELETE/api/admin/approval-configs/:idConfig löschen

Konfiguration: Groups, Configs & Closure Policy

Die Konfigurations-Ebene (Approval-Groups + Approval-Configs) wird in der UI unter Admin-Center → Service-Konfiguration → Genehmigungen verwaltet (/admin/approvals). Der Bereich hat drei Tabs: Groups, Configurations und Closure Policy (= Incident-Closure-Policy). Alle Admin-Endpoints erfordern eine Benutzer-Anmeldung; API-Keys werden nicht akzeptiert.

Approval-Group — Felder

FeldTypBeschreibung
nameString (1–50)Technischer Name, lowercase-alphanumerisch mit Bindestrichen
displayNameString (1–100)Anzeigename
descriptionString? (max. 500)Beschreibung
typeenumCAB, EMERGENCY_CAB, INCIDENT_CLOSURE, INCIDENT_REOPEN, MAJOR_INCIDENT, DATA_PROTECTION, CUSTOM
defaultStrategyenumANY, ALL, QUORUM, MAJORITY
defaultQuorumInt?Mindestzahl für QUORUM
isActiveBooleanAktiv/inaktiv (nur PATCH)
members[]userId + weight (1–10) + isBackup. eligible-members listet nur User mit der nötigen Approver-Permission.

POST und PATCH prüfen den Body streng: Ein Feld, das diese Tabelle nicht nennt, lehnt die API mit 400 ab. name wird nur beim Anlegen gesetzt, Mitglieder laufen über die members-Endpoints. Beim PATCH bleibt ein weggelassenes Feld unverändert; null leert description und defaultQuorum.

Approval-Config (Closure Policy) — Felder

Eine Approval-Config legt fest, OB und WIE eine Entität genehmigt werden muss. Für INCIDENT mit subType-Bezug zur Schließung ist genau das die „Closure Policy". Pro (entityType, subType) existiert höchstens eine Config (unique).

FeldTypBeschreibung
entityTypeenumCHANGE, INCIDENT, PROBLEM, CHANGE_TEMPLATE, WORKFLOW
subTypeString?z.B. CLOSURE, DATA_BREACH, EMERGENCY, MAJOR, P1, REOPEN … (verfeinert die Regel)
requiresApprovalBooleanDefault true. false → kein Approval nötig (Closure ohne Freigabe)
approvalGroupIdcuid?Welche Group genehmigt
strategy / quorumenum? / Int?Override; null = Group-Default verwenden
autoAssignBooleanDefault true — Approver automatisch aus der Group zuweisen
conditionsJSON?Bedingungs-Matching, z.B. {"riskLevel":["HIGH","VERY_HIGH"]}
priorityInt (0–100)Höher = zuerst geprüft (bei mehreren passenden Configs)
isActiveBooleanAktiv/inaktiv

Incident Closure Policy: Der Closure-Policy-Tab konfiguriert für INCIDENT, ob das Schließen eine Freigabe erfordert (requiresApproval), welche Group + Strategie greift und ggf. Bedingungen. Approver brauchen incidents.approveClosure; der SubType DATA_BREACH verlangt stattdessen incidents.acknowledgeDataBreach (DSGVO). Mehrere Approvals derselben Entität (z.B. Closure + Data-Breach) laufen parallel.

Incident Reopen Approval: Das Wiederöffnen eines geschlossenen Incidents ist standardmäßig genehmigungspflichtig (reopenRequiresApproval). Es läuft über eine eigene Approval-Gruppe vom Typ INCIDENT_REOPEN bzw. den subType REOPEN und über die eigene Approver-Berechtigung incidents.approveReopen. So bleibt die Reopen-Genehmigung vom Closure-Approval getrennt, und „darf schließen" und „darf wieder öffnen" können unterschiedliche Personenkreise sein. Der Reopen läuft über POST /api/incidents/:id/reopen; nach Freigabe (Entscheidung via POST /:id/decide) wird der Incident auf ACKNOWLEDGED gesetzt, bei Ablehnung bleibt er CLOSED. reopenOverride umgeht NIE die Approval-Pflicht. Reopen & Lifecycle

Approval-Strategien

Strategie Beschreibung Ergebnis
ALL Alle Approver müssen zustimmen APPROVED wenn alle zustimmen, REJECTED bei einer Ablehnung
ANY Ein einziger Approver reicht APPROVED bei erster Zustimmung
MAJORITY Einfache Mehrheit (>50%) APPROVED wenn >50% zustimmen
QUORUM Konfigurierbare Mindestzahl APPROVED wenn quorum-Anzahl zustimmt

API-Beispiele

Meine offenen Entscheidungen abrufen (cross-domain)

GET /api/approvals/inbox?types=CHANGE,HANDOVER_CONFIRM&limit=50&offset=0

Aggregiert über alle Provider; jeder Eintrag trägt seinen Quell-Typ und sagt, ob er direkt in der Liste entschieden werden kann (decideMode: inline) oder auf seine Seite verweist (deeplink). Beispiel (gekürzt):

{
  "data": [
    {
      "itemId": "CHANGE:approval-uuid-1",
      "type": "CHANGE",
      "entityId": "change-uuid",
      "entityNumber": "CHG-2026-000042",
      "title": "Upgrade PostgreSQL",
      "decideMode": "inline",
      "deeplinkUrl": "/changes/change-uuid",
      "inlineActions": { "rejectRequiresReason": true },
      "initiatedAt": "2026-03-17T10:00:00Z",
      "initiatedBy": { "id": "user-uuid", "name": "Jane Smith" },
      "priority": "HIGH"
    },
    {
      "itemId": "HANDOVER_CONFIRM:handover-uuid",
      "type": "HANDOVER_CONFIRM",
      "entityId": "handover-uuid",
      "entityNumber": "HO-00007",
      "title": "Dell XPS 15 Laptop",
      "decideMode": "deeplink",
      "deeplinkUrl": "/assets/handovers/handover-uuid",
      "initiatedAt": "2026-03-17T14:00:00Z"
    }
  ],
  "pagination": { "total": 2, "limit": 50, "offset": 0 },
  "counts": { "total": 2, "byType": { "CHANGE": 1, "HANDOVER_CONFIRM": 1 } }
}

Entschieden wird über POST /api/approvals/inbox/decide mit genau dieser itemId ({ itemId, decision: "APPROVE" | "REJECT", reason?, comment? }) — der Aggregator leitet anhand des Präfixes an den richtigen Provider weiter. Items mit rejectRequiresReason: true verlangen bei REJECT eine Begründung.

Entscheidung treffen

POST /api/approvals/:id/decide
{
  "decision": true,
  "comment": "Approved. Implementation plan looks solid."
}

Response

{
  "approval": {
    "id": "approval-uuid-1",
    "entityType": "CHANGE",
    "entityId": "change-uuid",
    "decision": true,
    "decisionAt": "2026-03-17T11:30:00Z",
    "comment": "Approved. Implementation plan looks solid."
  },
  "evaluation": {
    "isComplete": true,
    "outcome": "APPROVED",
    "approvals": 2,
    "rejections": 0,
    "pending": 0,
    "total": 2,
    "requiredForApproval": 2,
    "strategy": "ALL"
  }
}

Wenn die Evaluation ergibt, dass alle benötigten Approvals vorliegen, wird der Entity-Status automatisch aktualisiert (z.B. Change → APPROVED, Incident → CLOSED).

Genehmigungspflicht prüfen

GET /api/approvals/check?entityType=INCIDENT&subType=CLOSURE
{
  "requiresApproval": true,
  "strategy": "ALL",
  "approvalGroupId": "clx-group-incident-closure"
}

Der Endpoint liefert die Konfigurations-Metadaten für Create-/Close-Dialoge. Den laufenden Genehmigungsstand einer konkreten Entität trägt deren Detail-Payload (z.B. GET /api/changes/:id).

Verhalten bei Ablehnung

Bei Genehmigungsschritten in Workflows legt die Schritt-Konfiguration fest, was nach einer Ablehnung passiert:

Einstellung Verhalten
failOnReject (Standard: an)Der Workflow endet mit Status FAILED, sofern kein Eskalations-Schritt konfiguriert ist; der Initiator wird benachrichtigt.
failOnReject ausDer Workflow läuft mit den nächsten Schritten weiter.
escalationStepIdGreift bei jeder Ablehnung — von Hand wie automatisch — und geht failOnReject vor: statt zu scheitern, startet der angegebene Schritt. Benachrichtigt wird, wer diesen Schritt bearbeitet; führt ihn das System selbst aus, entfällt die Meldung, und lässt sich kein Bearbeiter bestimmen, geht sie an den Initiator.

Permissions

Permission Beschreibung
approvals.decideEntscheidungen buchen (zusätzlich zur Zuweisung und zum entity-spezifischen Approver-Recht)
approvals.viewGroupsApproval-Groups lesen (Settings-Tab Groups)
approvals.manageGroupsApproval-Groups anlegen/ändern/löschen
approvals.manageMembershipsGroup-Mitglieder verwalten (hinzufügen/ändern/entfernen)
approvals.viewConfigsApproval-Configs + Closure Policy lesen (Settings-Tabs Configs/Closure Policy)
approvals.manageConfigsApproval-Configs + Closure Policy verwalten

Wer entscheiden darf: Eine Entscheidung (POST /:id/decide bzw. /inbox/decide) setzt dreierlei voraus: (1) die Berechtigung approvals.decide; (2) die Entscheidung ist dem Aufrufer zugewiesen (sonst 403 NOT_ASSIGNED); (3) die Approver-Berechtigung des Entitätstyps — INCIDENT → incidents.approveClosure, INCIDENT:DATA_BREACH → incidents.acknowledgeDataBreach, INCIDENT:REOPEN → incidents.approveReopen, CHANGE/CHANGE_TEMPLATE → changes.approve, WORKFLOW → workflows.completeSteps. Bei kritischen Aktionen werden die Rechte mit dem aktuellen Stand aus der Datenbank geprüft, damit ein gerade entzogenes Recht sofort wirkt. Wer die Genehmigung angefordert hat, kann sie nicht selbst erteilen. Detail-Seite und Union-Inbox prüfen identisch.

Fehlerbehandlung

Error HTTP Beschreibung
APPROVAL_NOT_FOUND404Approval-ID existiert nicht
NOT_ASSIGNED403Approval ist nicht dem Aufrufer zugewiesen
ALREADY_DECIDED409Entscheidung wurde bereits getroffen
REJECTION_COMMENT_REQUIRED400Ablehnung erfordert einen Kommentar
NO_VALID_APPROVERS400Keine gültigen Approver konfiguriert
GROUP_IN_USE409Group wird in aktiven Configs verwendet
Verwandte Seiten
Changes API →

Change-Approvals im Detail

Incidents API →

Incident-Closure-Approval & DSGVO