{
 "openapi": "3.1.0",
 "info": {
  "title": "Lohnfluss API",
  "version": "1.0",
  "summary": "Deutsche Entgeltabrechnung als REST-API.",
  "description": "Rechnen, Dokumente erzeugen und die gesetzlichen Melde­verfahren bedienen.\n\n**Einheiten.** Alle Geldbeträge sind **Cent-Integer** und enden auf `_cent`.\nKein Float, nirgends. Stunden sind Dezimalzahlen, Daten `YYYY-MM-DD`,\nMonate `YYYY-MM`.\n\n**Mandantenmodell.** Ein *Partner* (z. B. eine Branchensoftware) verwaltet\nbeliebig viele *Mandanten* (Arbeitgeber). Ein Partner-Key darf auf alle\nMandanten seines Partners zugreifen, ein Mandanten-Key ausschließlich auf\nsich selbst.\n\n**Zeitscheiben.** Lohnrelevante Mitarbeiterdaten sind historisiert. Eine\nÄnderung ist deshalb nie ein Überschreiben, sondern eine neue Scheibe ab\n`gueltig_ab` — die vorherige wird zum Vortag geschlossen.\n\n**Baustand.** Rechnen, Dokumente und das Erzeugen der Melde­datensätze sind\ngebaut und amtlich verprobt. Endpunkte mit `x-baustand: zertifizierung`\nsind fertig entwickelt, brauchen aber ein externes Zertifikat bzw. einen\nBehörden-Zugang, um live zu übertragen.\n",
  "contact": {
   "name": "Lohnfluss",
   "url": "https://lohnfluss.de/kontakt"
  }
 },
 "servers": [
  {
   "url": "https://api.lohnfluss.de/v1",
   "description": "Produktion"
  }
 ],
 "security": [
  {
   "bearerAuth": []
  }
 ],
 "tags": [
  {
   "name": "Stammdaten",
   "description": "Arbeitgeber, Mitarbeiter mit Zeitscheiben, Bankverbindung, Kassenverzeichnis."
  },
  {
   "name": "Bewegungsdaten & Lohnlauf",
   "description": "Monatswerte melden, probeweise rechnen, festschreiben, korrigieren."
  },
  {
   "name": "Dokumente",
   "description": "Lohnabrechnung (§ 108 GewO), DATEV-Buchungsstapel, SEPA (pain.001), Digitale LohnSchnittstelle."
  },
  {
   "name": "SV-Meldeverfahren",
   "description": "DEÜV, Beitragsnachweis, AAG, EEL, eAU, A1, DSVV — Datensätze erzeugen und verwalten."
  },
  {
   "name": "Lohnsteuer (ELSTER)",
   "description": "Lohnsteuer-Anmeldung, Lohnsteuerbescheinigung, ELStAM."
  },
  {
   "name": "Posteingang",
   "description": "Eingehende Rückläufe und Anforderungen an einem Ort. Ablage und Endpunkte sind gebaut und testbar; echte Post kommt mit dem freigeschalteten Empfangskanal."
  },
  {
   "name": "Verwaltung",
   "description": "Benutzer und Rollen, Protokoll-Einsicht und API-Schlüssel. Schlüssel werden hier erzeugt und abgeschaltet — der Geheimwert ist nur im Moment der Erzeugung sichtbar."
  },
  {
   "name": "Service",
   "description": "Programmstand, Verfahrensversionen und Testkennung — was in jeder Meldung mitgeht."
  }
 ],
 "paths": {
  "/eingang": {
   "post": {
    "tags": [
     "Posteingang"
    ],
    "summary": "Eingegangene Meldedatei einspeisen",
    "description": "Nimmt den Inhalt einer von einer Datenannahmestelle eingegangenen Meldedatei entgegen,\nerkennt die enthaltenen Datensätze, ordnet sie über die Betriebsnummer des\nBeschäftigungsbetriebes (BBNR-AG) einem Mandanten zu und legt sie im Posteingang ab.\nWo ein Verfahren eine maschinelle Folge kennt (z. B. DSKK Meldegrund 06 → DSAK-Antwort),\nentsteht dabei ein **Entwurf** — gesendet wird nie automatisch.\n\nDerselbe Satz wird nicht zweimal verarbeitet (Sperre über einen Hash des Rohsatzes).\nNicht zuordenbare, unbekannte und fehlerhafte Sätze werden **nicht verworfen**, sondern in\nder Antwort benannt; der Aufrufer darf die Datei dann nicht löschen.\n\nSicherheitsgrenze: als Ziel kommen ausschließlich Mandanten des eigenen Partners in Frage.\n",
    "operationId": "eingangEinspeisen",
    "x-scope": "partner:mandanten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "roh"
        ],
        "properties": {
         "roh": {
          "type": "string",
          "description": "Inhalt der Meldedatei (ISO-8859-1",
          "Sätze zeilengetrennt)": null
         },
         "quelle": {
          "type": "string",
          "description": "Woher die Datei kam",
          "example": "gkv-komserver"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Verarbeitet. Die Listen benennen, was NICHT durchlief.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "gelesen": {
           "type": "integer",
           "description": "Nutzdatensätze ohne Umschlag (VOSZ/NCSZ/DSKO)"
          },
          "doppelt": {
           "type": "integer",
           "description": "bereits früher verarbeitete Sätze"
          },
          "verarbeitet": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "nicht_zuordenbar": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "unbekannt": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "fehler": {
           "type": "array",
           "items": {
            "type": "object"
           }
          }
         }
        }
       }
      }
     },
     "422": {
      "description": "Validierung fehlgeschlagen"
     }
    }
   }
  },
  "/mandanten": {
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Arbeitgeber (Mandant) anlegen",
    "operationId": "mandantAnlegen",
    "x-scope": "partner:mandanten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MandantEingabe"
       },
       "example": {
        "typ": "direkt",
        "name": "Muster Pflegedienst GmbH",
        "bundesland": "NW",
        "betriebsnummer": "12345678",
        "steuernummer": "5133081508159",
        "finanzamt_nr": "5133"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Angelegt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "id",
          "typ",
          "name"
         ],
         "properties": {
          "id": {
           "type": "integer",
           "example": 42
          },
          "typ": {
           "type": "string",
           "enum": [
            "cuvio",
            "direkt"
           ]
          },
          "name": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`name` oder `typ` fehlt bzw. `typ` ist weder `cuvio` noch `direkt`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   },
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Mandanten des Partners auflisten",
    "description": "Für das Mapping der eigenen `extern_ref`. Ein Mandanten-Key sieht hier nur sich selbst.",
    "operationId": "mandantenListe",
    "x-scope": "partner:mandanten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "mandanten": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/MandantKurz"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Mandant lesen",
    "operationId": "mandantLesen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Stammdaten.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Mandant"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     }
    }
   },
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Mandant ändern",
    "description": "Nur die mitgeschickten Felder werden geändert.",
    "operationId": "mandantAendern",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MandantEingabe"
       },
       "example": {
        "zahltag": 28,
        "erstattungssatz_u1": 70
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Geändert — `geaendert` nennt die tatsächlich geschriebenen Felder.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "geaendert": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "422": {
      "description": "Kein einziges änderbares Feld im Body.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/bank": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Auftraggeber-Bankverbindung setzen",
    "description": "Pflicht, bevor beim Festschreiben eine SEPA-Datei entstehen kann. Die bisherige\nVerbindung wird inaktiv gesetzt, die neue angelegt — die Historie bleibt erhalten.\n`bic` ist SEPA-Pflichtfeld (`DbtrAgt`), auch wenn Banken es im Alltag oft weglassen.\n",
    "operationId": "bankSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "kontoinhaber",
         "iban",
         "bic"
        ],
        "properties": {
         "kontoinhaber": {
          "type": "string",
          "example": "Muster Pflegedienst GmbH"
         },
         "iban": {
          "type": "string",
          "description": "Wird auf Prüfsumme geprüft; Leerzeichen sind erlaubt.",
          "example": "DE02120300000000202051"
         },
         "bic": {
          "type": "string",
          "minLength": 8,
          "maxLength": 11,
          "example": "BYLADEM1001"
         },
         "zweck_praefix": {
          "type": "string",
          "description": "Vorspann im Verwendungszweck jeder Zeile.",
          "example": "Lohn"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Gesetzt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "id": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`kontoinhaber` fehlt, IBAN ungültig oder BIC nicht 8/11 Zeichen — `fehler.feld` nennt das Feld.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/sepa-mandat": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "SEPA-Lastschriftmandat gegenüber einer Einzugsstelle erteilen oder widerrufen",
    "description": "**Nicht die Bankverbindung des Mandanten** (die ist die Zahlstelle für pain.001): das\nMandat ist die Ermächtigung der KRANKENKASSE, Beiträge einzuziehen. Gläubiger ist die\nKasse — sie vergibt Gläubiger-ID und Mandatsreferenz, und ein Arbeitgeber mit fünf Kassen\nhat fünf Mandate. Deshalb ist `kasse_ik` Pflicht.\n\nJede Änderung löst einen **DSAK mit Abgabegrund 02** aus (Pflichtenheft S. 139 ·\n66596d3b). Der **Widerruf** ist dort ein eigener meldepflichtiger Sachverhalt: er wird\ngemeldet, nicht gelöscht — die Kasse muss wissen, dass sie nicht mehr einziehen darf.\nDafür `widerrufen_am` setzen; das Mandat bleibt stehen.\n\nDie Antwort trägt bei der Erteilung den Hinweis, den das Pflichtenheft empfiehlt\n(S. 140 · cedc0577): „Das SEPA-Lastschriftmandat gilt für alle fälligen Beiträge\ninklusive etwaiger Mahngebühren und Säumniszuschläge.\"\n",
    "operationId": "sepaMandatSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "kasse_ik",
         "glaeubiger_id",
         "kontoinhaber",
         "iban",
         "erteilt_am"
        ],
        "properties": {
         "kasse_ik": {
          "type": "string",
          "description": "Institutionskennzeichen der einziehenden Einzugsstelle (9 Ziffern).",
          "example": "101575519"
         },
         "glaeubiger_id": {
          "type": "string",
          "maxLength": 35,
          "description": "SEPA-Gläubiger-Identifikationsnummer der Kasse. **Kein Ersatzwert** — ohne sie entsteht kein DBSL.",
          "example": "DE98ZZZ09999999999"
         },
         "mandatsreferenz": {
          "type": "string",
          "maxLength": 35,
          "description": "Von der Kasse vergeben; für den Anwender geführt, nicht im DBSL."
         },
         "kontoinhaber": {
          "type": "string",
          "example": "Muster Pflegedienst GmbH"
         },
         "iban": {
          "type": "string",
          "example": "DE02120300000000202051"
         },
         "erteilt_am": {
          "type": "string",
          "format": "date",
          "example": "2026-09-01"
         },
         "widerrufen_am": {
          "type": [
           "string",
           "null"
          ],
          "format": "date",
          "description": "Gesetzt = Widerruf (eigener meldepflichtiger Sachverhalt). Muss ab `erteilt_am` liegen."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Gesetzt. Bei der Erteilung mit dem empfohlenen Hinweistext.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "id": {
           "type": "integer"
          },
          "hinweis": {
           "type": "string",
           "description": "Nur bei der Erteilung."
          },
          "dsak": {
           "type": "array",
           "items": {
            "type": "object"
           },
           "description": "Erzeugte DSAK-Entwürfe."
          },
          "hinweise": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`kasse_ik`, `glaeubiger_id`, `kontoinhaber`, IBAN oder Datum fehlerhaft — `fehler.feld` nennt das Feld.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnarten": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Lohnarten-Stamm lesen",
    "description": "Alle Lohnarten des Mandanten und die **mitgelieferten** (Auslieferungs-Set, `eigene: false`).\n\nDie Lohnart trägt die beitragsrechtliche Steuerung des Entgeltbestandteils: `steuer_pflicht`,\n`sv_pflicht`, `uv_pflicht` und `ega` (einmalig gezahltes Arbeitsentgelt, § 23a SGB IV).\n\n⚠️ **`uv_pflicht` ist eigenständig, nicht aus `sv_pflicht` abgeleitet.** Was ins\nWertguthaben eingebracht wird, mindert das sv-pflichtige Entgelt — das uv-pflichtige nicht\n(Entstehungsprinzip).\n\n⚠️ **Der Stamm steuert die Rechnung noch nicht.** Er begleitet sie: weicht eine gepflegte\nLohnart von dem ab, was gerechnet wurde, erscheint das als Warnung am Lauf.\n",
    "operationId": "lohnartenLesen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "stichtag",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Ohne Angabe der heutige Tag."
     }
    ],
    "responses": {
     "200": {
      "description": "Liste.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "stichtag": {
           "type": "string",
           "format": "date"
          },
          "lohnarten": {
           "type": "array",
           "items": {
            "type": "object"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   },
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Eigene Lohnart anlegen oder ändern",
    "description": "Legt eine Lohnart des Mandanten an. **Eine eigene Lohnart geht der mitgelieferten mit\nderselben Nummer vor** — das Auslieferungs-Set bleibt unangetastet.\n\n⚠️ **Änderungen entstehen als ZEITSCHEIBE, nicht als Überschreiben:** ein anderes\n`gueltig_ab` legt eine neue Zeile an, die alte bleibt. Nur so ist beantwortbar, wie ein\nzurückliegender Monat gerechnet wurde (Pflichtenheft S. 102: „Die Lohnarten und deren\nÄnderungen — sofern sie sv-rechtliche Auswirkungen haben — werden historisch dokumentiert.\").\n",
    "operationId": "lohnartSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "nummer",
         "bezeichnung",
         "gueltig_ab"
        ],
        "properties": {
         "nummer": {
          "type": "string",
          "maxLength": 10,
          "example": "5000"
         },
         "bezeichnung": {
          "type": "string",
          "example": "Sachbezug (Haustarif)"
         },
         "bewegungsart": {
          "type": [
           "string",
           "null"
          ],
          "description": "Bewegungsart aus `lohn_bewegungen.art`; wird gegen deren Werte geprüft. NULL bei Lohnarten aus der Zeitscheibe (Grundgehalt, VWL, bAV)."
         },
         "steuer_pflicht": {
          "type": "boolean",
          "default": true
         },
         "sv_pflicht": {
          "type": "boolean",
          "default": true
         },
         "uv_pflicht": {
          "type": "boolean",
          "default": true
         },
         "ega": {
          "type": "boolean",
          "default": false
         },
         "gueltig_ab": {
          "type": "string",
          "format": "date"
         },
         "gueltig_bis": {
          "type": [
           "string",
           "null"
          ],
          "format": "date"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Angelegt oder geändert.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "id": {
           "type": [
            "integer",
            "null"
           ]
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`nummer`, `bezeichnung`, `gueltig_ab` fehlen oder `bewegungsart` gibt es nicht.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Mitarbeiter mit erster Zeitscheibe anlegen",
    "description": "Legt Stammdaten **und** die erste Zeitscheibe in einem Aufruf an. Ohne `gueltig_ab`\nbeginnt die Scheibe am `eintritt`.\n\nDer `taetigkeitsschluessel` wird gegen den amtlichen Katalog geprüft, sofern er\nmitgeschickt wird — ein falscher Schlüssel fiele sonst erst Monate später bei der\nEinzugsstelle auf, mit Korrekturmeldung.\n",
    "operationId": "mitarbeiterAnlegen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MitarbeiterEingabe"
       },
       "example": {
        "vorname": "Erika",
        "nachname": "Musterfrau",
        "geburtsdatum": "1990-05-14",
        "geschlecht": "w",
        "eintritt": "2026-03-15",
        "sv_nummer": "65140590M123",
        "steuer_id": "20013456978",
        "personengruppe": "101",
        "beitragsgruppe": "1111",
        "kasse_ik": "103121137",
        "vertrag": "gehalt",
        "taetigkeitsschluessel": "821012911",
        "steuerklasse": 1,
        "grundgehalt_cent": 315000
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Angelegt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "Pflichtfeld fehlt (`fehler.feld` nennt es) oder der Tätigkeitsschlüssel ist ungültig.\nPflicht sind: `vorname`, `nachname`, `geburtsdatum`, `geschlecht`, `eintritt`,\n`personengruppe`, `beitragsgruppe`, `kasse_ik`, `vertrag`.\n",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{maId}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "maId",
     "in": "path",
     "required": false,
     "description": "Ohne Angabe kommt die Liste aller Mitarbeiter, mit Angabe der einzelne inklusive aller Zeitscheiben.",
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Mitarbeiter lesen oder auflisten",
    "operationId": "mitarbeiterLesen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Einzelner Mitarbeiter mit `zeitscheiben[]` — ohne maId stattdessen die Liste unter `mitarbeiter`.",
      "content": {
       "application/json": {
        "schema": {
         "oneOf": [
          {
           "$ref": "#/components/schemas/MitarbeiterMitZeitscheiben"
          },
          {
           "type": "object",
           "properties": {
            "mitarbeiter": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/MitarbeiterKurz"
             }
            }
           }
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     }
    }
   },
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Mitarbeiter ändern (erzeugt eine neue Zeitscheibe)",
    "description": "Reine Stammdaten (Name, Anschrift, IBAN …) werden direkt geändert.\n\nSobald ein **zeitscheiben**-Feld im Body steht (Gehalt, Steuerklasse, Kasse,\nBeitragsgruppe …), ist `gueltig_ab` Pflicht: die bisherige Scheibe wird zum Vortag\ngeschlossen und eine neue angelegt — als Kopie der letzten plus den Änderungen.\nEin `gueltig_ab`, das nicht **nach** der letzten Scheibe liegt, wird abgewiesen.\n",
    "operationId": "mitarbeiterAendern",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MitarbeiterEingabe"
       },
       "example": {
        "gueltig_ab": "2026-07-01",
        "grundgehalt_cent": 330000
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Geändert.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "409": {
      "description": "`ZEITSCHEIBE_KONFLIKT` — `gueltig_ab` liegt nicht nach der letzten Scheibe.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Zeitscheiben-Felder ohne `gueltig_ab`, oder Tätigkeitsschlüssel ungültig.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/bewegungen/{monat}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "$ref": "#/components/parameters/monat"
    }
   ],
   "put": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Bewegungsdaten des Monats setzen",
    "description": "**Ersetzt** den Monat vollständig — der Aufruf ist damit von sich aus wiederholbar:\nalle bisherigen Zeilen des Monats werden gelöscht und durch die übergebenen ersetzt.\nIst der Monat bereits festgeschrieben, wird abgewiesen; dann führt nur noch der\nKorrekturlauf weiter.\n",
    "operationId": "bewegungenSetzen",
    "x-scope": "mandant:lohnlauf",
    "x-idempotent": true,
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "$ref": "#/components/parameters/idempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "mitarbeiter"
        ],
        "properties": {
         "mitarbeiter": {
          "type": "array",
          "items": {
           "type": "object",
           "properties": {
            "mitarbeiter_id": {
             "type": "integer"
            },
            "zeilen": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Bewegungszeile"
             }
            }
           }
          }
         }
        }
       },
       "example": {
        "mitarbeiter": [
         {
          "mitarbeiter_id": 17,
          "zeilen": [
           {
            "art": "stunden",
            "menge": 162.5
           },
           {
            "art": "zuschlag_nacht",
            "menge": 12,
            "prozent": 25
           },
           {
            "art": "einmalzahlung",
            "betrag_cent": 50000,
            "quelle_ref": "Praemie Q2"
           }
          ]
         }
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Gesetzt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "monat": {
           "type": "string"
          },
          "zeilen": {
           "type": "integer",
           "description": "Zahl der geschriebenen Zeilen."
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "409": {
      "description": "`LAUF_STATUS` — der Monat ist bereits festgeschrieben.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "`monat` ist nicht `YYYY-MM`, oder `mitarbeiter` ist kein Array.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   },
   "get": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Bewegungsdaten des Monats lesen",
    "operationId": "bewegungenLesen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Zeilen des Monats.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "monat": {
           "type": "string"
          },
          "zeilen": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Bewegungszeile"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnlauf/{monat}/probelauf": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "$ref": "#/components/parameters/monat"
    }
   ],
   "post": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Probeabrechnung rechnen",
    "description": "Rechnet den Monat durch, ohne festzuschreiben. Beliebig oft wiederholbar. Löst den Webhook `lohnlauf.probe_fertig` aus.",
    "operationId": "probelauf",
    "x-scope": "mandant:lohnlauf",
    "x-idempotent": true,
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "$ref": "#/components/parameters/idempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "Ergebnis mit Summen und Warnungen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/LaufErgebnis"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "409": {
      "description": "`LAUF_STATUS` — der Monat lässt sich in seinem Zustand nicht (mehr) probeweise rechnen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Fachlicher Fehler beim Rechnen (fehlende Stammdaten o. Ä.).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnlauf/{monat}/korrektur": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "$ref": "#/components/parameters/monat"
    }
   ],
   "post": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Korrekturlauf (Rückrechnung / Aufrollung)",
    "description": "Rechnet einen **festgeschriebenen** Monat periodengerecht neu und liefert das Delta\nsowie die daraus fälligen Korrektur-Meldungen. Legt einen eigenen Korrektur-Lauf ab;\nder ursprüngliche Lauf bleibt unangetastet.\n",
    "operationId": "korrekturlauf",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "folgemonat": {
          "type": "string",
          "description": "Monat, in dem das Delta ausgezahlt bzw. verrechnet wird. Ohne Angabe bleibt es beim Korrekturmonat.",
          "example": "2026-08"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Delta und erzeugte Korrektur-Meldungen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/LaufErgebnis"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "409": {
      "description": "`LAUF_STATUS` — der Monat ist nicht festgeschrieben, es gibt also nichts aufzurollen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Fachlicher Fehler beim Rechnen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnlauf/{monat}/festschreiben": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "$ref": "#/components/parameters/monat"
    }
   ],
   "post": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Lauf festschreiben und Dokumente erzeugen",
    "description": "Schreibt den Monat fest — ab dann sind Bewegungsdaten gesperrt und Änderungen laufen\nüber den Korrekturlauf. Im selben Zug entstehen Lohnabrechnungen, DATEV-Buchungsstapel,\nSEPA-Datei und ggf. weitere Dokumente.\n\nLöst die Webhooks `lohnlauf.festgeschrieben` und `dokumente.bereit` aus. Ein\nwiederholter Aufruf mit demselben `Idempotency-Key` liefert die gespeicherte Antwort\nund setzt `bereits: true`, statt ein zweites Mal zu schreiben.\n",
    "operationId": "festschreiben",
    "x-scope": "mandant:lohnlauf",
    "x-idempotent": true,
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "$ref": "#/components/parameters/idempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "Festgeschrieben, mit erzeugten Dokumenten.",
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "$ref": "#/components/schemas/LaufErgebnis"
          },
          {
           "type": "object",
           "properties": {
            "bereits": {
             "type": "boolean",
             "description": "true = war schon festgeschrieben, es wurde nichts neu erzeugt."
            },
            "dokumente": {
             "type": "object",
             "description": "Zusammenfassung der erzeugten Dateien."
            }
           }
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "409": {
      "description": "Drei Fälle:\n\n- `LAUF_BEFUNDE` — die Prüfkette hat **Fehler** gefunden. Aus einem festgeschriebenen\n  Lauf entstehen Meldungen; mit diesen Angaben dürfte keine entstehen. Die Antwort\n  trägt zusätzlich `befunde` mit der Liste dessen, was es verhindert — sonst könnte\n  der Aufrufer nur „irgendwo ist ein Fehler\" sagen, ohne zu benennen wo.\n  **Warnungen halten nicht auf.**\n- `LAUF_STATUS` — es gibt keinen Probelauf, oder der Lauf ist in einem anderen Stand.\n- `IDEMPOTENZ_KONFLIKT` — derselbe Key wurde mit anderem Inhalt verwendet.\n",
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "$ref": "#/components/schemas/Fehler"
          },
          {
           "type": "object",
           "properties": {
            "befunde": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Befund"
             }
            }
           }
          }
         ]
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnlauf/{monat}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "$ref": "#/components/parameters/monat"
    }
   ],
   "get": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Lauf-Status und Summen je Mitarbeiter",
    "operationId": "lohnlaufLesen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Der jüngste Lauf des Monats.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "lauf_id": {
           "type": [
            "integer",
            "null"
           ],
           "description": "`null`, solange nicht gerechnet wurde."
          },
          "status": {
           "type": [
            "string",
            "null"
           ],
           "example": "festgeschrieben",
           "description": "`null` heißt: für diesen Monat wurde noch kein Probelauf gerechnet. Das ist\nein Zustand, kein Fehler — die Antwort ist trotzdem 200 mit leerer Liste\nund den Befunden, damit sich Beanstandungen **vor** dem Rechnen beheben\nlassen.\n"
          },
          "monat": {
           "type": "string"
          },
          "festgeschrieben_am": {
           "type": [
            "string",
            "null"
           ],
           "format": "date-time"
          },
          "festgeschrieben_von": {
           "type": [
            "string",
            "null"
           ]
          },
          "befunde": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Befund"
           },
           "description": "Wird bei **jedem** Abruf frisch ermittelt, nicht beim Probelauf eingefroren:\nzwischen Rechnen und Festschreiben kann sich ein Stammdatum ändern.\n"
          },
          "warnungen": {
           "type": "array",
           "items": {
            "type": "string"
           },
           "description": "Hinweise der **letzten Berechnung** dieses Laufs — anders als `befunde`\nein eingefrorener Stand, denn sie beschreiben, was beim Rechnen geschah.\n\n⚠️ **Hier steht auch, wer NICHT abgerechnet wurde.** Ein Beschäftigter ohne\nhinterlegten Stundenlohn oder ohne erfasste Stunden fällt aus dem Lauf; die\nübrigen Abrechnungen sind korrekt, der **Beitragsnachweis meldet dann aber\nzu wenig**. Wer diese Liste ignoriert, merkt es erst bei der Krankenkasse.\nBis zum 13.08.2026 standen die Hinweise nur in der Antwort des Probelaufs\nund waren danach nicht mehr abrufbar.\n"
          },
          "je_mitarbeiter": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "mitarbeiter_id": {
              "type": "integer"
             },
             "name": {
              "type": "string",
              "example": "Musterfrau, Erika"
             },
             "brutto_cent": {
              "type": "integer"
             },
             "lst_cent": {
              "type": "integer"
             },
             "soli_cent": {
              "type": "integer"
             },
             "kist_cent": {
              "type": "integer"
             },
             "sv_an_cent": {
              "type": "integer",
              "description": "Arbeitnehmeranteil KV+RV+AV+PV zusammen."
             },
             "netto_cent": {
              "type": "integer"
             },
             "auszahlung_cent": {
              "type": "integer"
             },
             "ag_kosten_cent": {
              "type": "integer",
              "description": "Arbeitgeber-Gesamtkosten."
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`monat` ist kein YYYY-MM.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnlauf/{monat}/dokumente": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "$ref": "#/components/parameters/monat"
    }
   ],
   "get": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Dokumente eines Laufs auflisten",
    "operationId": "dokumenteListe",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste der Dateien; heruntergeladen wird über `GET /dokumente/{dokId}`.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "dokumente": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Dokument"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/dokumente/{dokId}": {
   "parameters": [
    {
     "name": "dokId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Dokument herunterladen",
    "description": "Liefert die Datei als Download. Der Content-Type richtet sich nach dem Typ:\n`payslip` → PDF, `buchungsstapel` → CSV, `sepa` → XML, `dls` → ZIP.\n",
    "operationId": "dokumentLaden",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Die Datei.",
      "content": {
       "application/pdf": {
        "schema": {
         "type": "string",
         "format": "binary"
        }
       },
       "text/csv": {
        "schema": {
         "type": "string"
        }
       },
       "application/xml": {
        "schema": {
         "type": "string"
        }
       },
       "application/zip": {
        "schema": {
         "type": "string",
         "format": "binary"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "description": "Das Dokument gehört zu einem fremden Mandanten.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "410": {
      "description": "Der Datensatz existiert, die Datei aber nicht mehr.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/dokumente": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Alle Dokumente eines Mandanten",
    "description": "Bislang gab es Dokumente **nur je Lauf**. Wer die Entgeltabrechnungen einer Person über\ndas Jahr sucht oder das Lohnkonto von 2025, musste jeden Monat einzeln abfragen.\n\nDer **Monat** stammt aus dem Lauf; Jahresdokumente (Lohnkonto, DLS) haben keinen Lauf und\ntragen ihr Jahr im Dateinamen.\n",
    "operationId": "dokumenteListe",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "typ",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "payslip",
        "lohnjournal",
        "lohnkonto",
        "buchungsstapel",
        "sepa",
        "lstb",
        "meldebestaetigung",
        "dls"
       ]
      }
     },
     {
      "name": "jahr",
      "in": "query",
      "schema": {
       "type": "string",
       "pattern": "^\\\\d{4}$"
      }
     },
     {
      "name": "mitarbeiter_id",
      "in": "query",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 500,
       "maximum": 2000
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Liste.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "dokumente": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "typ": {
              "type": "string"
             },
             "dateiname": {
              "type": "string"
             },
             "mitarbeiter_id": {
              "type": [
               "integer",
               "null"
              ]
             },
             "vorname": {
              "type": [
               "string",
               "null"
              ]
             },
             "nachname": {
              "type": [
               "string",
               "null"
              ]
             },
             "monat": {
              "type": [
               "string",
               "null"
              ],
              "description": "Nur bei Monatsdokumenten."
             },
             "sha256": {
              "type": "string"
             },
             "created_at": {
              "type": "string",
              "format": "date-time"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`jahr` ist kein JJJJ.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldebescheinigungen/fehlend": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Übermittelte DEÜV-Meldungen ohne Bescheinigung nach § 28a Abs. 5 SGB IV",
    "description": "Vollzähligkeitsprüfung (Pflichtenheft S. 199): zu jeder übermittelten Meldung gehört eine\nBescheinigung an den Beschäftigten. Die Betriebsautomatik erzeugt sie stündlich; diese Liste\nzeigt, was noch fehlt. `?auch_entwuerfe=1` zählt auch nicht übermittelte Meldungen.\n",
    "operationId": "meldebescheinigungenFehlend",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "auch_entwuerfe",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "1"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Liste der Meldungen ohne Bescheinigung",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "fehlend": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "meldung_id": {
              "type": "integer"
             },
             "mitarbeiter_id": {
              "type": [
               "integer",
               "null"
              ]
             },
             "status": {
              "type": "string"
             },
             "gesendet_am": {
              "type": [
               "string",
               "null"
              ],
              "format": "date-time"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldebescheinigungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Bescheinigungen nach § 28a Abs. 5 SGB IV erzeugen",
    "description": "Erzeugt je übermittelter DEÜV-Meldung ein PDF mit **allen gemeldeten Daten** (gelesen aus dem\nübermittelten Datensatz, nicht aus den Parametern) und legt es wie eine Lohnunterlage ab\n(`lohn_dokumente`, Typ `meldebestaetigung`, sha256, Audit). Download über `GET /dokumente/{dokId}`.\n\nOhne `meldung_ids` werden alle **fehlenden** erzeugt. Eine Bescheinigung zu einer noch nicht\nübermittelten Meldung entsteht nur mit `auch_entwuerfe: true` und ist **als Entwurf gekennzeichnet**\n(Wasserzeichen, Dateiname `ENTWURF_…`); in der Sandbox zusätzlich `SANDBOX_…`. Idempotent: eine\nvorhandene Bescheinigung wird nicht ersetzt.\n",
    "operationId": "meldebescheinigungenErzeugen",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "meldung_ids": {
          "type": "array",
          "items": {
           "type": "integer"
          },
          "description": "Nur diese Meldungen (sonst alle fehlenden)"
         },
         "auch_entwuerfe": {
          "type": "boolean",
          "description": "Auch nicht übermittelte Meldungen bescheinigen — als Entwurf gekennzeichnet"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Erzeugt",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "erzeugt": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "meldung_id": {
              "type": "integer"
             },
             "dokument_id": {
              "type": "integer"
             },
             "dateiname": {
              "type": "string"
             },
             "entwurf": {
              "type": "boolean"
             }
            }
           }
          },
          "uebersprungen": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "meldung_id": {
              "type": "integer"
             },
             "grund": {
              "type": "string"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/fehlerprotokoll/{monat}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "monat",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string",
      "pattern": "^\\\\d{4}-\\\\d{2}$"
     }
    }
   ],
   "post": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Fehlerprotokoll eines Monats erzeugen (PDF)",
    "description": "Pflichtenheft S. 173: nicht plausible Daten und Tatbestände in EINEM Protokoll — Prüfketten- und Lauf-Befunde,\namtliche Kernprüfung der gespeicherten Meldungen (Fehlertexte), Fehler-Rückmeldungen und offene Fristen des\nPosteingangs. Ersetzt eine ältere Fassung desselben Monats; Download über `GET /mandanten/{id}/dokumente/{id}`.\n",
    "operationId": "fehlerprotokollErzeugen",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Dokument abgelegt (`dokument_id`, `eintraege`, `fehler`)."
     },
     "422": {
      "description": "monat ungültig."
     }
    }
   }
  },
  "/mandanten/{mandantId}/lohnkonto/{jahr}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "jahr",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string",
      "pattern": "^\\\\d{4}$"
     }
    }
   ],
   "post": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Jahres-Lohnkonten erzeugen",
    "description": "§ 41 Abs. 1 EStG i.V.m. § 4 LStDV: für jeden Arbeitnehmer und jedes Kalenderjahr ist ein\nLohnkonto zu führen. Erzeugt wird je Arbeitnehmer ein PDF; der Download läuft über\n`GET /dokumente/{dokId}`.\n\n⚠️ Gerechnet wird ausschließlich aus **festgeschriebenen** Läufen — ein Probelauf ist\nfolgenlos und darf nicht in ein Dokument wandern, das als Nachweis dient.\n\nIdempotent: eine erneute Anforderung ersetzt die vorherige Fassung desselben Jahres.\n",
    "operationId": "lohnkontenErzeugen",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Erzeugt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "jahr": {
           "type": "integer"
          },
          "erzeugt": {
           "type": "integer"
          },
          "uebersprungen": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "mitarbeiter_id": {
              "type": "integer"
             },
             "grund": {
              "type": "string"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "409": {
      "description": "`KEINE_DATEN` — für das Jahr ist kein Monat festgeschrieben.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "`jahr` ist kein JJJJ.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/dls/{jahr}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "jahr",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string",
      "pattern": "^\\d{4}$"
     },
     "example": "2026"
    }
   ],
   "post": {
    "tags": [
     "Dokumente"
    ],
    "summary": "Digitale LohnSchnittstelle exportieren",
    "description": "Erzeugt den DLS-Export nach § 4 Abs. 2a LStDV für ein Kalenderjahr (Format des amtlichen BZSt-Pakets). Heruntergeladen wird er über `GET /dokumente/{dokId}`.",
    "operationId": "dlsExport",
    "x-scope": "mandant:dokumente:lesen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Export erzeugt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "dokument_id": {
           "type": "integer"
          },
          "dateiname": {
           "type": "string"
          },
          "kennzahlen": {
           "type": "object",
           "description": "Zusammenfassung des Exports (Zahl der Mitarbeiter, Zeiträume)."
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "`jahr` ist nicht vierstellig.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`DLS` — der Export ist fachlich nicht möglich (keine Läufe im Jahr o. Ä.).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/programmstand": {
   "get": {
    "tags": [
     "Service"
    ],
    "summary": "Programmstand, Identifier und Verfahrensversionen",
    "description": "Für die ITSG-Systemuntersuchung und für jeden, der wissen will, womit gerechnet wurde.\n\n⚠️ Die **Prod-/Mod-ID steht in jeder Meldung**. Solange die ITSG keine vergeben hat, geht\neine erkennbare Platzhalter-Kennung hinaus (`vergeben: false`) — echte Übermittlungen sind\ndamit nicht zulässig.\n\n`elster_echtbetrieb: false` heißt: alles geht mit Testkennung hinaus. Das ist der\nNormalzustand bis zur Zulassung. Zugangsdaten oder Umgebungswerte stehen hier nicht.\n",
    "operationId": "programmstand",
    "x-scope": null,
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Der Stand.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "programm": {
           "type": "object",
           "properties": {
            "name": {
             "type": "string"
            },
            "version": {
             "type": "string"
            },
            "hersteller": {
             "type": "string"
            }
           }
          },
          "identifier": {
           "type": "object",
           "properties": {
            "prod_id": {
             "type": "string"
            },
            "mod_id": {
             "type": "string"
            },
            "vergeben": {
             "type": "boolean"
            },
            "hinweis": {
             "type": [
              "string",
              "null"
             ]
            }
           }
          },
          "elster_echtbetrieb": {
           "type": "boolean"
          },
          "verfahrensversionen": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "ab": {
              "type": "string",
              "format": "date"
             },
             "bis": {
              "type": [
               "string",
               "null"
              ],
              "format": "date"
             },
             "verfahren": {
              "type": "string"
             },
             "quelle": {
              "type": "string"
             }
            }
           }
          },
          "gilt_jetzt": {
           "type": [
            "object",
            "null"
           ]
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/protokoll": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Protokoll (Audit-Log) des Mandanten",
    "description": "Wer hat wann was geändert. Für die ITSG-Systemuntersuchung ist die Nachvollziehbarkeit ein\neigener Prüfpunkt; die Daten lagen seit jeher in `lohn_audit_log`, einsehen konnte sie\nniemand außer über die Datenbank.\n\n⚠️ Die Einträge enthalten personenbezogene Daten — das ist ihr Zweck. Sie bleiben deshalb\nhinter `mandant:verwaltung` und liefern nur den eigenen Mandanten.\n",
    "operationId": "protokoll",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "tabelle",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "z. B. `lohn_mitarbeiter`"
     },
     {
      "name": "zeilen_id",
      "in": "query",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "aktion",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "insert",
        "update",
        "delete"
       ]
      }
     },
     {
      "name": "von",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "bis",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 200,
       "maximum": 1000
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Einträge, neueste zuerst.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "eintraege": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "tabelle": {
              "type": "string"
             },
             "zeilen_id": {
              "type": "integer"
             },
             "aktion": {
              "type": "string"
             },
             "akteur": {
              "type": "string"
             },
             "created_at": {
              "type": "string",
              "format": "date-time"
             },
             "alt": {
              "type": [
               "object",
               "null"
              ]
             },
             "neu": {
              "type": [
               "object",
               "null"
              ]
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/protokoll.csv": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Protokoll als CSV (für die Betriebsprüfung)",
    "description": "Ein Prüfer bekommt keinen Datenbankzugang und liest kein JSON am Bildschirm. Er will eine\nDatei, die er ablegen und in seiner eigenen Software öffnen kann.\n\nTrennzeichen **Semikolon**, Kodierung **UTF-8 mit BOM** — so öffnet Excel in einer\ndeutschen Windows-Umgebung ohne Import-Dialog und ohne zerschossene Umlaute.\n",
    "operationId": "protokollCsv",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "tabelle",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "von",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "bis",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "CSV-Datei.",
      "content": {
       "text/csv": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/benutzer/{id}/einladung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Einladung erzeugen (Passwort setzen lassen)",
    "description": "Der Weg, auf dem ein neuer Benutzer zu seinem Passwort kommt.\n\n⚠️ `POST /benutzer` legt einen Benutzer mit **leerem** Passwort-Hash an und verwies auf\neinen „Zurücksetzen-Weg\", den es nicht gab — ein so angelegter Benutzer konnte sich **nie**\nanmelden.\n\nDas Klartext-Token wird **genau einmal** zurückgegeben; in der Datenbank steht nur sein\nHash. Der Administrator gibt es auf einem anderen Weg weiter — eine Mail-Strecke gibt es\nnoch nicht. Eingelöst wird es über `POST /portal/passwort-setzen` (ohne Anmeldung).\n",
    "operationId": "benutzerEinladung",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Einladung erzeugt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "benutzer_id": {
           "type": "integer"
          },
          "email": {
           "type": "string"
          },
          "token": {
           "type": "string",
           "description": "Nur EINMAL sichtbar."
          },
          "gueltig_bis_minuten": {
           "type": "integer"
          },
          "hinweis": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "409": {
      "description": "Das Konto ist deaktiviert.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{maId}/vortraege/{jahr}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "maId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    },
    {
     "name": "jahr",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     },
     "example": 2026
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Vortragswerte eines Jahres lesen",
    "description": "Die Jahres-Anfangsbestände beim Programm- oder Arbeitgeberwechsel. Höchstens ein Satz je\nArt.\n",
    "operationId": "vortraegeLesen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Vorhandene Vorträge des Jahres.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "jahr": {
           "type": "integer"
          },
          "vortraege": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Vortrag"
           }
          }
         }
        },
        "example": {
         "jahr": 2026,
         "vortraege": [
          {
           "art": "eigene_firma",
           "quelle": "Lexware lohn+gehalt, Januar–April",
           "brutto_cent": 1200000,
           "lohnsteuer_cent": 150000,
           "soli_cent": 0,
           "kirchensteuer_cent": 4000,
           "svbrutto_laufend_cent": 1200000,
           "einmalzahlung_cent": 0,
           "sv_tage": 120
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     }
    }
   },
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Vortragswerte setzen oder ersetzen",
    "description": "Legt den Satz an oder überschreibt ihn (je Person, Jahr und Art höchstens einer — zwei\nSätze derselben Art wären zwei Wahrheiten).\n\n⚠️ **Die beiden Arten wirken verschieden, und sie zu vermischen bescheinigt fremden\nArbeitslohn als eigenen:**\n\n- `eigene_firma` — Wechsel des **Abrechnungssystems**. Derselbe Arbeitgeber, dasselbe\n  Dienstverhältnis. Die Werte gehören **in** die Lohnsteuerbescheinigung, weil sie das\n  ganze Jahr dieses Verhältnisses abdeckt, und in die SV-Luft nach § 23a.\n- `fremdfirma` — unterjähriger Eintritt von einem **anderen** Arbeitgeber. Die Werte\n  gehören **nicht** in unsere Bescheinigung; der frühere Arbeitgeber stellt seine eigene\n  aus. Sie dienen der Lohnsteuer auf sonstige Bezüge und entscheiden den **Großbuchstaben\n  S**.\n\n⚠️ SV-Werte bei `fremdfirma` werden mit **422** abgewiesen: die SV-Luft ist\narbeitgeberbezogen, ein früherer Arbeitgeber verbraucht sie nicht mit. Sie stillschweigend\nzu ignorieren hieße, den Anwender im Glauben zu lassen, es wirke.\n",
    "operationId": "vortraegeSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "allOf": [
         {
          "$ref": "#/components/schemas/Vortrag"
         },
         {
          "type": "object",
          "required": [
           "art"
          ]
         }
        ]
       },
       "example": {
        "art": "fremdfirma",
        "quelle": "Voriger Arbeitgeber, Januar–März",
        "brutto_cent": 900000,
        "lohnsteuer_cent": 110000
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Gesetzt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "mitarbeiter_id": {
           "type": "integer"
          },
          "jahr": {
           "type": "integer"
          },
          "art": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "422": {
      "description": "Art unbekannt, Betrag negativ, oder SV-Werte an einem Fremdfirmen-Vortrag.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/api-schluessel": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "API-Schlüssel des Mandanten auflisten",
    "description": "Listet die Schlüssel **ohne** ihren Geheimwert — der ist nur im Moment der Erzeugung\nsichtbar. Zurück kommt, was man zum Wiedererkennen und Abschalten braucht: Bezeichnung,\nBerechtigungen, ob er aktiv ist und wann er zuletzt benutzt wurde.\n\nDie Antwort führt zusätzlich den **Katalog der vergebbaren Berechtigungen** mit\n(`verfuegbare_scopes`). Eine Oberfläche müsste ihn sonst selbst pflegen — und wäre die\nnächste Liste, die von den Routen abweicht.\n",
    "operationId": "apiSchluesselListe",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Schlüssel und vergebbare Berechtigungen.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "schluessel": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/ApiSchluessel"
           }
          },
          "verfuegbare_scopes": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "scope": {
              "type": "string",
              "example": "mandant:lohnlauf"
             },
             "titel": {
              "type": "string",
              "example": "Abrechnung"
             },
             "zweck": {
              "type": "string"
             }
            }
           }
          }
         }
        },
        "example": {
         "schluessel": [
          {
           "id": 7,
           "label": "Zeiterfassung Produktiv",
           "scopes": [
            "mandant:stammdaten",
            "mandant:lohnlauf"
           ],
           "aktiv": 1,
           "created_at": "2026-08-09T10:12:00Z",
           "zuletzt_benutzt_am": "2026-08-09T11:40:00Z"
          }
         ],
         "verfuegbare_scopes": [
          {
           "scope": "mandant:lohnlauf",
           "titel": "Abrechnung",
           "zweck": "Bewegungsdaten schreiben, Probelauf rechnen, festschreiben, Korrekturlauf anstoßen."
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   },
   "post": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "API-Schlüssel erzeugen",
    "description": "⚠️ **Der Schlüssel wird genau einmal zurückgegeben.** Gespeichert wird nur sein\nSHA-256-Hash; wir können ihn nicht erneut anzeigen, nur ersetzen. Dieselbe Regel wie bei\nder Benutzer-Einladung — wer die Datenbank liest, soll keine fremde Anbindung übernehmen\nkönnen.\n\n**Ein Mandant kann sich keinen Partner-Scope geben.** `partner:mandanten` sieht alle\nMandanten eines Partners; selbst ausgestellt wäre er ein Weg an fremde Gehaltsdaten.\nDer Scope existiert, ist hier aber verboten — die Antwort sagt das mit **403**, nicht mit\n„unbekannt\".\n\nGehört der Mandant zur Sandbox, trägt der Schlüssel zwingend das Präfix `lk_test_` —\ndie Umgebung folgt dem **Mandanten**, sie ist keine Eingabe des Aufrufers.\nDie Kennzeichnung folgt dem Mandanten, nicht dem Wunsch des Aufrufers.\n",
    "operationId": "apiSchluesselAnlegen",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "label",
         "scopes"
        ],
        "properties": {
         "label": {
          "type": "string",
          "maxLength": 120,
          "description": "Wofür der Schlüssel da ist — er taucht im Protokoll als Akteur auf."
         },
         "scopes": {
          "type": "array",
          "minItems": 1,
          "items": {
           "type": "string"
          },
          "description": "Mindestens einer. Nur `mandant:*` ist selbst vergebbar."
         },
         "test": {
          "type": "boolean",
          "description": "Erzwingt einen Test-Schlüssel. Bei einem Testmandanten ohnehin gesetzt."
         }
        }
       },
       "example": {
        "label": "Zeiterfassung Produktiv",
        "scopes": [
         "mandant:stammdaten",
         "mandant:lohnlauf"
        ]
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Angelegt — mit dem einmalig sichtbaren Schlüssel.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "label": {
           "type": "string"
          },
          "scopes": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "test": {
           "type": "boolean"
          },
          "schluessel": {
           "type": "string",
           "description": "⚠️ Nur EINMAL sichtbar.",
           "example": "lk_live_9f2c…"
          },
          "hinweis": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "description": "Scope fehlt — oder ein Partner-Scope wurde selbst angefordert.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Label fehlt, keine Scopes, oder ein Scope ist unbekannt.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/api-schluessel/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "delete": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "API-Schlüssel abschalten",
    "description": "Setzt den Schlüssel auf inaktiv; die Zeile bleibt bestehen. Bewusst kein echtes Löschen —\nProtokoll und `zuletzt_benutzt_am` sollen nachvollziehbar bleiben, gerade wenn ein\nSchlüssel wegen eines Verdachts abgeschaltet wird.\n\n⚠️ **Ein Schlüssel kann sich nicht selbst abschalten** (409). Sonst nimmt sich ein\nIntegrator mit einem Aufruf den Zugang, mit dem er ihn zurückholen könnte — dieselbe\nFalle wie beim letzten Administrator.\n",
    "operationId": "apiSchluesselAbschalten",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Abgeschaltet (oder war es schon).",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "aktiv": {
           "type": "boolean"
          },
          "unveraendert": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "409": {
      "description": "Der eigene Schlüssel kann sich nicht selbst abschalten.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/stammdaten/fehlzeitenschluessel": {
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Fehlzeitenkatalog (Anlage 03 zum Pflichtenheft)",
    "description": "Die amtlichen Fehlzeitenschlüssel mit Art der Fehlzeit und ihrer Wirkung im DEÜV-Meldewesen\n(aus `referenz/itsg_pflichtenheft/anlage03_fehlzeitenkatalog.json`, erzeugt von\n`scripts/itsg/anlage03_extrakt.js`). `POST/PATCH …/fehlzeiten` weist einen Schlüssel ab, der\nhier nicht steht. Braucht **keinen** Scope.\n",
    "operationId": "fehlzeitenschluesselListe",
    "x-scope": null,
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Katalog.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "quelle": {
           "type": "string"
          },
          "schluessel": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "schluessel": {
              "type": "string",
              "example": "1.6"
             },
             "art": {
              "type": "string"
             },
             "deuev": {
              "type": "string",
              "description": "Wirkung im DEÜV-Meldewesen laut Anlage 03."
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     }
    }
   }
  },
  "/stammdaten/kassen": {
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Krankenkassen-Verzeichnis",
    "description": "Die zum heutigen Tag gültigen Kassen aus der amtlichen GKV-Stammdatendatei, mit\nInstitutionskennzeichen, Zusatzbeitrag und U2-Satz. Braucht **keinen** Scope —\nein gültiger API-Key genügt.\n",
    "operationId": "kassenListe",
    "x-scope": null,
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Kassen.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "kassen": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "ik": {
              "type": "string",
              "example": "103121137"
             },
             "name": {
              "type": "string",
              "example": "BKK firmus"
             },
             "kassenart": {
              "type": "string",
              "example": "BKK"
             },
             "zusatzbeitrag": {
              "type": "string",
              "description": "Prozent, z. B. \"2.50\"."
             },
             "u2_satz": {
              "type": "string",
              "description": "Prozent."
             },
             "bbnr": {
              "type": [
               "string",
               "null"
              ],
              "description": "Betriebsnummer der Kasse aus der Stammdatendatei (Schlüssel der Unbedenklichkeitsbescheinigung); null",
              "solange der Sync sie nicht geliefert hat.": null
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "SV-Meldung erzeugen",
    "description": "Baut aus Stammdaten und Anlass den amtlichen Datensatz und legt ihn als Entwurf ab.\nDer Datensatz läuft dabei durch die amtliche GKV-Kernprüfung.\n\nDie **Annahmestelle** (Empfänger) kann explizit übergeben werden; sonst wird sie aus\ndem Routing-Verzeichnis anhand von Verfahren und Kasse aufgelöst.\n",
    "operationId": "meldungErzeugen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "verfahren"
        ],
        "properties": {
         "verfahren": {
          "type": "string",
          "enum": [
           "deuev",
           "beitragsnachweis",
           "aag",
           "dsvv",
           "eel",
           "eau",
           "a1"
          ]
         },
         "mitarbeiter_id": {
          "type": "integer",
          "description": "Pflicht bei allen Verfahren außer `beitragsnachweis` (der ist betriebsbezogen)."
         },
         "anlass": {
          "type": "object",
          "description": "Verfahrensabhängige Anlass-Daten (Grund, Zeitraum, Entgelt …)."
         },
         "annahmestelle_bbnr": {
          "type": "string",
          "description": "Betriebsnummer der Annahmestelle. Ohne Angabe wird sie aufgelöst."
         },
         "kasse_bbnr": {
          "type": "string"
         },
         "kasse_ik": {
          "type": "string"
         },
         "lauf_id": {
          "type": "integer"
         },
         "erstellt": {
          "type": "string",
          "format": "date-time"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Entwurf angelegt.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/MeldungKurz"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "description": "Mitarbeiter unbekannt.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "`verfahren` unbekannt, `mitarbeiter_id` fehlt, oder `ANNAHMESTELLE` nicht auflösbar.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   },
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Meldungen auflisten",
    "description": "Die 200 jüngsten Meldungen, ohne Datensatz-Inhalt.",
    "operationId": "meldungenListe",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "meldungen": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Meldung"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Meldung inklusive Datensatz lesen",
    "operationId": "meldungLesen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Meldung mit `datensatz` und dem Ergebnis der Kernprüfung.",
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "$ref": "#/components/schemas/Meldung"
          },
          {
           "type": "object",
           "properties": {
            "datensatz": {
             "type": "string",
             "description": "Der amtliche Datensatz im Format aus `datensatz_format`."
            },
            "kernpruefung_meldung": {
             "type": [
              "string",
              "null"
             ]
            }
           }
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     }
    }
   },
   "patch": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Meldung freigeben oder Freigabe zurückziehen",
    "description": "Setzt `geprueft` (**Freigabe**) oder zurück auf `entwurf` (**Zurückziehen**).\n\n⚠️ Die Freigabe ist der Punkt, an dem personenbezogene Daten an eine Einzugsstelle gehen —\neine bewusste Handlung, kein Formalakt. `meldungen/transport/versand.js` greift\nausschließlich **freigegebene** Meldungen auf; er läuft nicht von selbst.\n\nEine Meldung, die die **Kernprüfung nicht bestanden** hat, lässt sich nicht freigeben: sie\nwürde von der Annahmestelle zurückgewiesen, und bis dahin hielte der Betrieb sie für\nerledigt, während die Frist läuft.\n\nZurückziehen geht nur **vor** dem Versand. Danach ist es keine Rücknahme mehr, sondern\neine Storno-Meldung — ein eigener Vorgang.\n",
    "operationId": "meldungFreigeben",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "status"
        ],
        "properties": {
         "status": {
          "type": "string",
          "enum": [
           "geprueft",
           "entwurf"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Freigegeben bzw. zurückgezogen.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "status": {
           "type": "string"
          },
          "hinweis": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "409": {
      "description": "`MELDUNG_STATUS` — der Übergang passt nicht zum aktuellen Stand.\n`KERNPRUEFUNG` — die Meldung hat die Kernprüfung nicht bestanden.\n",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Ein anderer Zielstatus als `geprueft`/`entwurf`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldeanlaesse": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Lebensereignis → alle fälligen Meldungen",
    "description": "Der bequeme Weg: **ein** Ereignis melden (Eintritt, Austritt, Krankheit, Elternzeit …)\nund alle daraus folgenden Meldungen entstehen zusammen. Läuft in einer Transaktion —\nscheitert eine, entsteht keine.\n",
    "operationId": "meldeanlass",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "typ"
        ],
        "properties": {
         "typ": {
          "type": "string",
          "description": "Ereignistyp. Bei unbekanntem Typ nennt `fehler.detail` die erlaubten Werte.",
          "example": "eintritt"
         },
         "mitarbeiter_id": {
          "type": "integer"
         },
         "datum": {
          "type": "string",
          "format": "date"
         },
         "annahmestelle_bbnr": {
          "type": "string"
         },
         "kasse_ik": {
          "type": "string"
         },
         "lauf_id": {
          "type": "integer"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Erzeugte Meldungen.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "anlass": {
           "type": "string"
          },
          "erzeugt": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/MeldungKurz"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "description": "Mitarbeiter unbekannt.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Unbekannter Meldeanlass, fehlende `mitarbeiter_id`, oder `ANNAHMESTELLE` nicht auflösbar.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/posteingang": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Posteingang"
    ],
    "summary": "Posteingang auflisten",
    "description": "Eingehende Rückmeldungen, Anforderungen und ELStAM-Mitteilungen — die Datenbasis für eine Inbox. `offen` eignet sich als Badge-Zähler.",
    "operationId": "posteingangListe",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "neu",
        "gelesen",
        "erledigt"
       ]
      }
     },
     {
      "name": "kategorie",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Einträge und Zahl der offenen.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "offen": {
           "type": "integer"
          },
          "eintraege": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/PosteingangEintrag"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/posteingang/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Posteingang"
    ],
    "summary": "Posteingang-Eintrag lesen",
    "operationId": "posteingangLesen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Eintrag.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PosteingangEintrag"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     }
    }
   },
   "patch": {
    "tags": [
     "Posteingang"
    ],
    "summary": "Status setzen",
    "operationId": "posteingangStatus",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "status"
        ],
        "properties": {
         "status": {
          "type": "string",
          "enum": [
           "neu",
           "gelesen",
           "erledigt"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Gesetzt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "status": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "422": {
      "description": "Status ungültig — `fehler.detail` nennt die erlaubten Werte.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lsta/{zeitraum}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "zeitraum",
     "in": "path",
     "required": true,
     "description": "Anmeldezeitraum — Monat `YYYY-MM`, Quartal `YYYY-Qn` oder Jahr `YYYY`.",
     "schema": {
      "type": "string"
     },
     "example": "2026-07"
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "Lohnsteuer-Anmeldung vorbereiten",
    "description": "Berechnet die BMF-Kennzahlen aus den Läufen des Zeitraums und legt den Entwurf ab. Übermittelt wird getrennt.",
    "operationId": "lstaVorbereiten",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Entwurf mit Kennzahlen und Hinweisen.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "zeitraum": {
           "type": "string"
          },
          "kennzahlen": {
           "type": "object"
          },
          "hinweise": {
           "type": "array",
           "items": {
            "type": "string"
           },
           "description": "Fehlende oder unplausible Stammdaten — blockieren den Entwurf nicht, wohl aber die Übermittlung."
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`LSTA` — der Entwurf ist fachlich nicht möglich.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   },
   "get": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "LStA-Entwürfe des Zeitraums lesen",
    "operationId": "lstaLesen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwürfe, jüngster zuerst.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "meldungen": {
           "type": "array",
           "items": {
            "type": "object"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/lsta/{zeitraum}/uebermitteln": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "zeitraum",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string"
     }
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "Lohnsteuer-Anmeldung an ELSTER übermitteln",
    "description": "Übermittelt den jüngsten Entwurf des Zeitraums über ERiC. Ohne verfügbare\nERiC-Bibliothek antwortet der Endpunkt mit `501 ERIC_FEHLT`.\n",
    "operationId": "lstaUebermitteln",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "zertifizierung",
    "responses": {
     "200": {
      "description": "Übermittelt — mit Transferticket.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "transferticket": {
           "type": [
            "string",
            "null"
           ]
          },
          "returncode": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "description": "Kein Entwurf für den Zeitraum.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "`LSTA` — ERiC hat den Datensatz abgewiesen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "423": {
      "description": "`KEINE_FREIGABE` / `SANDBOX_KEIN_VERSAND` — Betriebs-Riegel oder Freigabe geschlossen bzw. Sandbox-Mandant; es wurde nichts gesendet.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "501": {
      "description": "`ERIC_FEHLT` — auf dieser Instanz ist ERiC nicht eingerichtet.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/lstb/{vz}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "vz",
     "in": "path",
     "required": true,
     "description": "Veranlagungszeitraum (Kalenderjahr).",
     "schema": {
      "type": "string",
      "pattern": "^\\d{4}$"
     },
     "example": "2026"
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "Lohnsteuerbescheinigungen des Jahres erzeugen",
    "description": "Bildet je Mitarbeiter die Jahreswerte aus den Läufen des VZ und legt die Bescheinigung als Entwurf ab. Ohne `mitarbeiter_id` für alle.",
    "operationId": "lstbErzeugen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "mitarbeiter_id": {
          "type": "integer",
          "description": "Nur für diesen Mitarbeiter."
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Entwürfe angelegt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ergebnisse": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "mitarbeiter_id": {
              "type": "integer"
             },
             "status": {
              "type": "string"
             },
             "hinweise": {
              "type": "array",
              "items": {
               "type": "string"
              }
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`LSTB` — z. B. keine Läufe im Veranlagungszeitraum.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   },
   "get": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "LStB-Entwürfe des Jahres lesen",
    "operationId": "lstbLesen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwürfe je Mitarbeiter.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "meldungen": {
           "type": "array",
           "items": {
            "type": "object"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{mitarbeiterId}/elstam/{anlass}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "mitarbeiterId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    },
    {
     "$ref": "#/components/parameters/elstamAnlass"
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "ELStAM-Entwurf je Mitarbeiter",
    "description": "Legt An-, Ab- oder Ummeldung beim Finanzamt als Entwurf ab. Die Daten kommen aus\nEin-/Austritt des Mitarbeiters, lassen sich aber überschreiben.\n",
    "operationId": "elstamEntwurfMitarbeiter",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "referenzdatum": {
          "type": "string",
          "format": "date"
         },
         "beschaeftigungsbeginn": {
          "type": "string",
          "format": "date"
         },
         "abmeldedatum": {
          "type": "string",
          "format": "date"
         },
         "hauptarbeitgeber": {
          "type": "boolean",
          "default": true
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Entwurf angelegt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`ELSTAM` — z. B. fehlende Steuer-IdNr.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{mitarbeiterId}/elstam/{anlass}/uebermitteln": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "mitarbeiterId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    },
    {
     "$ref": "#/components/parameters/elstamAnlass"
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "ELStAM-Meldung übermitteln",
    "operationId": "elstamUebermitteln",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "zertifizierung",
    "responses": {
     "200": {
      "description": "Übermittelt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "description": "Kein Entwurf für Mitarbeiter und Anlass.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "`ELSTAM` — ERiC hat abgewiesen.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "423": {
      "description": "`KEINE_FREIGABE` / `SANDBOX_KEIN_VERSAND` — Betriebs-Riegel oder Freigabe geschlossen bzw. Sandbox-Mandant; es wurde nichts gesendet.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "501": {
      "description": "`ERIC_FEHLT` — ERiC ist auf dieser Instanz nicht eingerichtet.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/elstam/anmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "ELStAM-Meldung auf Mandantenebene",
    "description": "Wie der mitarbeiterbezogene Entwurf, aber mit `mitarbeiter_id` im Body — praktisch für Massenanlage.",
    "operationId": "elstamAnmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "mitarbeiter_id"
        ],
        "properties": {
         "mitarbeiter_id": {
          "type": "integer"
         },
         "anlass": {
          "type": "string",
          "enum": [
           "anmeldung",
           "abmeldung",
           "ummeldung"
          ],
          "default": "anmeldung"
         },
         "referenzdatum": {
          "type": "string",
          "format": "date"
         },
         "hauptarbeitgeber": {
          "type": "boolean",
          "default": true
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Entwurf angelegt, inklusive Datensatz.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "verfahren": {
           "type": "string",
           "example": "elstam"
          },
          "anlass": {
           "type": "string"
          },
          "status": {
           "type": "string",
           "example": "entwurf"
          },
          "datensatz": {
           "type": "object"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "description": "Mitarbeiter unbekannt.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "`mitarbeiter_id` fehlt oder der Datensatz ist unvollständig.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/elstam/aenderungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Lohnsteuer (ELSTER)"
    ],
    "summary": "Eingehende ELStAM-Änderungsliste verarbeiten",
    "description": "Das „Abo\": geänderte Steuerabzugsmerkmale vom Finanzamt einspielen. Je Änderung\nentsteht eine neue Mitarbeiter-Zeitscheibe und ein Posteingang-Eintrag.\n",
    "operationId": "elstamAenderungen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "aenderungen"
        ],
        "properties": {
         "aenderungen": {
          "type": "array",
          "minItems": 1,
          "items": {
           "type": "object",
           "required": [
            "idnr",
            "gueltig_ab"
           ],
           "properties": {
            "idnr": {
             "type": "string",
             "description": "Steuer-Identifikationsnummer des Arbeitnehmers."
            },
            "gueltig_ab": {
             "type": "string",
             "format": "date"
            },
            "steuerklasse": {
             "type": "integer"
            },
            "faktor": {
             "type": "number"
            },
            "kinderfreibetraege": {
             "type": "number"
            },
            "kist_merkmal": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Ergebnis je Änderung.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "verarbeitet": {
           "type": "integer"
          },
          "ergebnis": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "idnr": {
              "type": "string"
             },
             "status": {
              "type": "string"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`aenderungen[]` fehlt oder ist leer.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{maId}/zeitscheiben/{zsId}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "maId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    },
    {
     "name": "zsId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Zeitscheibe berichtigen",
    "description": "**Berichtigung**, nicht Änderung. `PATCH .../mitarbeiter/{maId}` legt bei jeder Änderung\neine NEUE Zeitscheibe an — richtig, wenn sich etwas *geändert* hat („ab 1. Juli\nSteuerklasse III\"). Falsch, wenn sich jemand *vertippt* hat: dann bliebe die falsche\nAngabe für den Zeitraum davor stehen und würde weiter gemeldet und abgerechnet.\n\n⚠️ Der Gültigkeitszeitraum lässt sich hier **nicht** verschieben (das beträfe die\nNachbarscheibe) und die Berichtigung wird **abgewiesen**, sobald der Zeitraum einen\nfestgeschriebenen, gemeldeten oder abgeschlossenen Lauf berührt — dann ist der\nKorrekturlauf der richtige Weg.\n",
    "operationId": "zeitscheibeBerichtigen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MitarbeiterEingabe"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Berichtigt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "id": {
           "type": "integer"
          },
          "berichtigt": {
           "type": "array",
           "items": {
            "type": "string"
           },
           "description": "die tatsächlich geänderten Spalten"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "409": {
      "description": "`LAUF_FESTGESCHRIEBEN` — für den Zeitraum ist bereits abgerechnet. Die betroffenen\nMonate stehen im Meldungstext.\n",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Unzulässiger Wert oder Versuch, den Gültigkeitszeitraum zu verschieben.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/bewegungen/{monat}/mitarbeiter/{maId}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "monat",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string",
      "pattern": "^\\\\d{4}-\\\\d{2}$"
     }
    },
    {
     "name": "maId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "put": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Bewegungen eines Mitarbeiters für einen Monat ersetzen",
    "description": "Ersetzt **nur** die Zeilen dieser Person in diesem Monat.\n\n⚠️ Der Unterschied zu `PUT /bewegungen/{monat}` ist wesentlich: der ersetzt den **ganzen\nMonat** (löscht erst alle Zeilen des Mandanten). Für den maschinellen Push ist das\nrichtig, für eine Oberfläche eine Falle — wer die Stunden *einer* Person nachträgt und\nnur diese schickt, löscht die Bewegungen aller anderen. Ohne Fehlermeldung.\n\nAntwortet mit `409 LAUF_STATUS`, sobald der Monat festgeschrieben, gemeldet oder\nabgeschlossen ist. `hinweise` benennt Zeilen mit Bewegungsarten **ohne Wirkung**\n(`fehlzeit_krank`, `urlaub`) — sie werden gespeichert, ändern aber nichts an der\nAbrechnung.\n",
    "operationId": "bewegungenMitarbeiterSetzen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "zeilen"
        ],
        "properties": {
         "zeilen": {
          "type": "array",
          "items": {
           "$ref": "#/components/schemas/Bewegungszeile"
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Ersetzt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "monat": {
           "type": "string"
          },
          "mitarbeiter_id": {
           "type": "integer"
          },
          "zeilen": {
           "type": "integer"
          },
          "hinweise": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "409": {
      "description": "`LAUF_STATUS` — der Monat ist bereits abgerechnet.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "422": {
      "description": "Unbekannte Bewegungsart oder unplausibler Wert; `fehler.feld` nennt es.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/fehlzeiten": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Fehlzeiten des Mandanten",
    "description": "Alle Fehlzeiten, mit `monat` gefiltert auf die, die den Monat **berühren**.\n\n⚠️ Nicht „die im Monat beginnen\": eine Krankheit vom 25.03. bis 14.04. gehört in beide\nMonate, weil sie in beiden Ausfalltage erzeugt. Wer nur nach dem Beginn filtert,\nübersieht in der Monatsansicht genau die langen Fälle.\n",
    "operationId": "fehlzeitenMandant",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "monat",
      "in": "query",
      "schema": {
       "type": "string",
       "pattern": "^\\\\d{4}-\\\\d{2}$"
      },
      "description": "Nur Fehlzeiten, die diesen Monat berühren."
     }
    ],
    "responses": {
     "200": {
      "description": "Liste.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "monat": {
           "type": [
            "string",
            "null"
           ]
          },
          "fehlzeiten": {
           "type": "array",
           "items": {
            "allOf": [
             {
              "$ref": "#/components/schemas/Fehlzeit"
             },
             {
              "type": "object",
              "properties": {
               "mitarbeiter_id": {
                "type": "integer"
               },
               "vorname": {
                "type": "string"
               },
               "nachname": {
                "type": "string"
               }
              }
             }
            ]
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "422": {
      "description": "`monat` ist kein YYYY-MM.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{maId}/fehlzeiten": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "maId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Fehlzeiten eines Mitarbeiters",
    "operationId": "fehlzeitenListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste"
     }
    }
   },
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Fehlzeit erfassen",
    "description": "An den Fehlzeiten hängen vier Fachblöcke: die Abmeldung mit Grund 34 nach einem Zeitmonat\n(`spezifikation = ohne_entgeltfortzahlung_krankengeld`), die Aussteuerung\n(`nach_ablauf_krankengeld`), die AAG-Erstattung (`typ = mutterschutz` bzw.\n`beschaeftigungsverbot`) und die Kurzarbeit.\n\n`typ = mutterschutz` und `beschaeftigungsverbot` führen **nie** zu einer Abmeldung —\nwer nur auf die `spezifikation` schaut, meldet Beschäftigte mitten im Mutterschutz ab.\n\n**`typ = kind_krank`** (EEL-Block E3, 23.08.2026): Freistellung wegen Erkrankung oder stationärer Mitaufnahme\neines Kindes (§ 45 SGB V) → Entgeltbescheinigung KV bei Kinderkrankengeld (DSLW Grund 02, DBFR), sobald der\nFreistellungsmonat festgeschrieben ist. Pflicht: `kind_id` (Kinder: `…/mitarbeiter/{maId}/kinder`), `vae_ersttag`\n(am ersten Tag noch voll gearbeitet/bezahlt?), `freistellung_anspruch` (`vollstaendig` | `teilweise` |\n`ausgeschlossen_tarifvertrag` | `ausgeschlossen_betriebsvereinbarung` | `ausgeschlossen_arbeitsvertrag`) —\nbei `teilweise` zusätzlich `bezahlt_von`/`bezahlt_bis`; optional `stationaer`, `bezahlt_tage_begrenzt`\n(BEGRZFREIST). Nur der **unbezahlte** Teil kürzt das Entgelt; FREISTBRUTTO/-NETTO entstehen aus Brutto 1 − Brutto 2\nmit dem Fiktivnetto der Abrechnung. Fehlt eine Angabe, entsteht keine Bescheinigung (Hürde), kein Ersatzwert.\n\n**`typ = krankheit` mit `au = 1`** löst — wenn die Regel es zulässt (GKV, frühere attestierte AU in der\n6-Monats-Kette, zusammen ≥ 30 Tage; offenes Ende = heute + 7) — die **Vorerkrankungsanfrage (EEL Grund 41)** als\nEntwurf aus (`vorerkrankungsanfrage` in der Antwort; Pflichtenheft S. 226/227).\n",
    "operationId": "fehlzeitAnlegen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Angelegt (`id`); bei attestierter Krankheit ggf. `vorerkrankungsanfrage` (Entwurf 41 oder Hürden)."
     }
    }
   }
  },
  "/mandanten/{mandantId}/fehlzeiten/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Fehlzeit ändern",
    "operationId": "fehlzeitAendern",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Geändert"
     }
    }
   },
   "delete": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Fehlzeit löschen",
    "description": "Zulässig — eine irrtümlich erfasste Fehlzeit ist kein Geschäftsvorfall. Der Vorgang wird\naber protokolliert, sonst fällt in der Betriebsprüfung eine Lücke auf, die niemand mehr\nerklären kann.\n",
    "operationId": "fehlzeitLoeschen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "204": {
      "description": "Gelöscht"
     }
    }
   }
  },
  "/mandanten/{mandantId}/betriebsstaetten": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Beschäftigungsbetriebe des Mandanten (BBNRVU) mit Hauptbetriebsnummer",
    "description": "Pflichtenheft S. 331 (ec586c06 · 1721b032 · e0b8a69d): ein Arbeitgeber darf für mehrere\nBeschäftigungsbetriebe mehrere Betriebsnummern führen; **genau eine** ist die\nHauptbetriebsnummer (HABBNR), unter der die Beitragsnachweise abgegeben werden. In der\nMeldung steht als Verursacher (BBNRVU) die Nummer des Betriebs, in dem der Beschäftigte\ntatsächlich arbeitet — zugeordnet über `betriebsstaette_id` an der Zeitscheibe.\n\nOhne erfasste Betriebsstätten gilt die Betriebsnummer des Mandanten (`quelle: mandant`);\ndas ist der Regelfall. `befund` ist gefüllt, wenn keine oder mehrere Nummern als Haupt\ngekennzeichnet sind — dann lässt sich kein Beitragsnachweis abgeben.\n",
    "operationId": "betriebsstaettenListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "monat",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "pattern": "^\\d{4}-\\d{2}$"
      },
      "description": "Betriebsstätten können eröffnet und geschlossen werden — Stichmonat"
     }
    ],
    "responses": {
     "200": {
      "description": "`betriebsstaetten[]`, `hauptbetriebsnummer`, `quelle`, `befund`"
     }
    }
   },
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Beschäftigungsbetrieb anlegen",
    "description": "`haupt: true` nimmt der bisherigen Hauptbetriebsnummer ihre Kennzeichnung — genau eine je\nMandant (1721b032). Die Betriebsnummer wird auf ihre Prüfziffer geprüft.\n",
    "operationId": "betriebsstaetteAnlegen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "betriebsnummer",
         "bezeichnung"
        ],
        "properties": {
         "betriebsnummer": {
          "type": "string",
          "pattern": "^\\d{8}$"
         },
         "bezeichnung": {
          "type": "string"
         },
         "haupt": {
          "type": "boolean"
         },
         "gueltig_ab": {
          "type": "string",
          "format": "date",
          "nullable": true
         },
         "gueltig_bis": {
          "type": "string",
          "format": "date",
          "nullable": true
         },
         "rechtskreis": {
          "type": "string",
          "enum": [
           "W",
           "O"
          ],
          "nullable": true
         },
         "anschrift_plz": {
          "type": "string",
          "nullable": true
         },
         "anschrift_ort": {
          "type": "string",
          "nullable": true
         },
         "anschrift_strasse": {
          "type": "string",
          "nullable": true
         },
         "anschrift_hausnummer": {
          "type": "string",
          "nullable": true
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "`{ id }`"
     },
     "409": {
      "description": "die Betriebsnummer ist für den Mandanten bereits erfasst"
     },
     "422": {
      "description": "Prüfziffer oder Pflichtfeld"
     }
    }
   }
  },
  "/mandanten/{mandantId}/betriebsstaetten/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Beschäftigungsbetrieb ändern",
    "operationId": "betriebsstaetteAendern",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "`{ id, geaendert }`"
     }
    }
   },
   "delete": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Beschäftigungsbetrieb löschen",
    "description": "Nur, solange keine Zeitscheibe darauf zeigt. Wer einen Betrieb schließt, setzt\n`gueltig_bis` — sonst verlieren bereits gemeldete Zeiträume ihre Betriebsnummer.\n",
    "operationId": "betriebsstaetteLoeschen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`{ geloescht }`"
     },
     "409": {
      "description": "Zeitscheiben zeigen auf diese Betriebsstätte"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{maId}/kinder": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "maId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Kinder eines Mitarbeiters (kindbezogene Kinderkrankengeld-Freistellungen)",
    "description": "Pflichtenheft S. 219: Freistellungen wegen Erkrankung eines Kindes sind **je Kind** zu führen (BEZFREIST-JAHR zählt\ndie bezahlten Tage desselben Kindes im Kalenderjahr). `gesetzlich_versichert` leer = unbekannt → die Bescheinigung\nGrund 02 entsteht nicht, bis es beantwortet ist (Kinderkrankengeld setzt GKV-Versicherung des Kindes voraus).\n",
    "operationId": "kinderListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`kinder[]` (id, vorname, geburtsdatum, verstorben_am, gesetzlich_versichert, bemerkung)"
     }
    }
   },
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Kind anlegen",
    "operationId": "kindAnlegen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "vorname"
        ],
        "properties": {
         "vorname": {
          "type": "string",
          "maxLength": 60
         },
         "geburtsdatum": {
          "type": "string",
          "format": "date"
         },
         "verstorben_am": {
          "type": "string",
          "format": "date",
          "nullable": true,
          "description": "Sterbetag des Kindes. Die Berücksichtigung beim PV-Abschlag endet mit **Ablauf\ndieses Monats** — dieselbe Grenze wie beim 25. Geburtstag (§ 188 BGB). Ohne\nAngabe zählt das Kind weiter.\n"
         },
         "gesetzlich_versichert": {
          "type": "integer",
          "enum": [
           0,
           1
          ],
          "nullable": true
         },
         "bemerkung": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Angelegt (`id`)"
     },
     "422": {
      "description": "Validierung"
     }
    }
   }
  },
  "/mandanten/{mandantId}/kinder/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Kind ändern",
    "operationId": "kindAendern",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Geändert"
     }
    }
   },
   "delete": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Kind löschen (nur ohne Fehlzeiten-Bezug)",
    "operationId": "kindLoeschen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "204": {
      "description": "Gelöscht"
     },
     "409": {
      "description": "An Fehlzeiten „Kind krank\" hinterlegt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{maId}/pfaendungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "maId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Pfändungen eines Mitarbeiters",
    "operationId": "pfaendungenListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste"
     }
    }
   },
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Pfändung erfassen",
    "description": "Der `rang` entscheidet die Reihenfolge der Befriedigung (§ 804 Abs. 3 ZPO). Zwei aktive\nPfändungen mit demselben Rang werden angenommen, aber mit einem Hinweis quittiert — die\nReihenfolge ist dann nicht eindeutig, und das ist eine Rechtsfrage, keine Rechenfrage.\n",
    "operationId": "pfaendungAnlegen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Angelegt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/pfaendungen/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "patch": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Pfändung ändern",
    "operationId": "pfaendungAendern",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Geändert"
     }
    }
   }
  },
  "/mandanten/{mandantId}/produktivreife": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Bewegungsdaten & Lohnlauf"
    ],
    "summary": "Kann dieser Mandant produktiv abgerechnet werden? (Blocker / Meldung / Hinweis)",
    "description": "Dasselbe Urteil wie `npm run produktivreife` — vor dem Lauf: **BLOCKER** (die Person fiele\nstill aus dem Lauf), **MELDUNG** (rechnet, aber eine Pflichtmeldung wäre unvollständig),\n**HINWEIS**. Die Fachbefunde kommen aus der Prüfkette, dem einen Pfad, den auch der Lohnlauf nimmt.\n`?monat=JJJJ-MM` (Vorgabe: laufender Monat). Grundlage der Startseite „Heute\" im Portal.\n",
    "operationId": "produktivreife",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "monat",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "pattern": "^[0-9]{4}-[0-9]{2}$"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Urteil",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "monat": {
           "type": "string"
          },
          "produktivreif": {
           "type": "boolean"
          },
          "aktiv": {
           "type": "integer"
          },
          "rechenbar": {
           "type": [
            "integer",
            "null"
           ]
          },
          "funde": {
           "type": "object",
           "properties": {
            "BLOCKER": {
             "type": "array",
             "items": {
              "type": "object",
              "properties": {
               "wer": {
                "type": "string"
               },
               "was": {
                "type": "string"
               }
              }
             }
            },
            "MELDUNG": {
             "type": "array",
             "items": {
              "type": "object",
              "properties": {
               "wer": {
                "type": "string"
               },
               "was": {
                "type": "string"
               }
              }
             }
            },
            "HINWEIS": {
             "type": "array",
             "items": {
              "type": "object",
              "properties": {
               "wer": {
                "type": "string"
               },
               "was": {
                "type": "string"
               }
              }
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/u1-wahl": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "U1-Erstattungssatz je Krankenkasse",
    "description": "Der Erstattungssatz ist eine Wahl gegenüber **jeder Kasse einzeln** — jede regelt ihre\nSätze in der eigenen Satzung, und ein Satz, den eine Kasse nicht anbietet, ist dort nicht\nwählbar. Geliefert werden nur die Kassen, die im Bestand tatsächlich vorkommen, je mit\nden angebotenen Sätzen, der Wahl und dem daraus folgenden **Umlagesatz**.\n\n`erstattungssatz_u1` am Mandanten bleibt als Vorgabewert bestehen und greift, solange für\neine Kasse nichts gewählt ist. Passt auch er nicht, weist `hinweis` aus, mit welchem Satz\nstattdessen gerechnet wird.\n",
    "operationId": "u1WahlListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Kassen mit angebotenen Sätzen und Wahl"
     }
    }
   }
  },
  "/mandanten/{mandantId}/u1-wahl/{kasseIk}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "kasseIk",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string"
     }
    }
   ],
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Erstattungssatz für eine Kasse wählen",
    "description": "`erstattungssatz: null` nimmt die Wahl zurück — dann greift wieder der Vorgabewert des\nMandanten. Die Wahl ist eine **Zeitscheibe**: `gueltig_ab` (Vorgabe: 1. Januar des\nlaufenden Jahres) legt fest, ab wann sie gilt, damit eine Nachberechnung den damals\ngewählten Satz trifft.\n",
    "operationId": "u1WahlSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Gespeichert"
     }
    }
   }
  },
  "/mandanten/{mandantId}/uv/stammdatenabruf": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "UV-Stammdatenabruf (DSAS) beim DGUV-Stammdatendienst anstoßen",
    "description": "**Vorverfahren zum Lohnnachweis:** vor der Abgabe des elektronischen Lohnnachweises ist ein\nStammdatenabgleich mit dem Stammdatendienst durchzuführen — gemeldet werden dürfen nur die vom\nDienst zurückgemeldeten Gefahrtarifstellen. Es entsteht ein **DSAS-Entwurf** in `lohn_meldungen`;\ngesendet wird er wie jede andere Meldung erst nach Freigabe.\n\nBody: `meldejahr` (JJJJ), optional `storno: true`.\n\n⚠️ **Zeitfenster:** frühestens ab dem 1. November des Vorjahres; spätestens im Dezember des\nMeldejahres (die Betriebsautomatik erinnert an beides). ⚠️ **Erst- oder Folgeabfrage** entscheidet\ndas System selbst an BBNRUV/BBNRLB/BBNRAS — nicht an der PIN und nicht an der Unternehmensnummer;\ndie von der DGUV zugeteilte laufende Nummer geht ab dem zweiten Jahr zwingend mit.\n⚠️ **Storno** trägt die laufende Nummer, mit der die Ursprungsmeldung ABGESCHICKT wurde — bei einer\nInitialabfrage also `000`, auch wenn die DGUV inzwischen eine laufende Nummer vergeben hat. Zulässig\nnur, solange im betroffenen Zeitraum noch kein Lohnnachweis erstellt wurde.\n\n**Gesperrt (409):** Beitragsmaßstab 4/5/6 (kein Lohnnachweis), landwirtschaftliche BG (Anlage 19a),\nUV-Träger der öffentlichen Hand (Anlage 19b), Arbeitgeber ist selbst Unternehmen eines UV-Trägers\n(Anlage 19c, Stammdatum `uv_arbeitgeber_ist_traeger`), Träger-Betriebsnummer als meldende Stelle\n(Anlagen 7/8), Träger nimmt am Verfahren nicht teil.\n",
    "operationId": "uvStammdatenabruf",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "meldejahr"
        ],
        "properties": {
         "meldejahr": {
          "type": "integer",
          "example": 2027
         },
         "storno": {
          "type": "boolean"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "DSAS-Entwurf angelegt (`meldung_id`, `vorgangs_id`, `lfd_nr`, `erstabfrage`)"
     },
     "404": {
      "description": "Storno ohne vorhandenen Abruf"
     },
     "409": {
      "description": "Gesperrt (`UV_ABRUF_GESPERRT`), Storno unzulässig (`UV_STORNO_GESPERRT`) oder für das Meldejahr ist bereits ein Abruf übermittelt (`UV_ABRUF_VORHANDEN` — erst stornieren)"
     },
     "422": {
      "description": "Zugangsdaten unvollständig, Zeitfenster verfehlt oder Datensatz nicht erzeugbar"
     }
    }
   }
  },
  "/mandanten/{mandantId}/uv/lohnnachweis/korrektur": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Übermittelten Lohnnachweis korrigieren (Storno + Neumeldung)",
    "description": "Bei nachträglichen Änderungen der **stornorelevanten** Inhalte eines bereits übermittelten\nLohnnachweises entstehen zwei Entwürfe: die Stornierung und die Neumeldung. Gesendet wird\nnichts; in der Übermittlungsdatei steht der Storno vor der Neumeldung.\n\n⚠️ **Eine ausschließliche Änderung der UV-Stunden führt NICHT zur Stornierung** — die Route\nantwortet dann mit 200 und dem Grund, ohne etwas anzulegen.\n\n⚠️ **Der Storno entsteht nur zusammen mit einem inhaltlich fehlerfreien Korrektur-DSLN.** Wäre\nder Korrektursatz fehlerhaft, bleibt alles wie es war (200 mit `huerden`) — eine Stornierung\nohne Ersatz ließe den Betrieb für das Jahr ohne Nachweis dastehen.\n\nAusnahme `ohne_neumeldung: true` — nur bei rückwirkender Beendigung der meldenden Stelle und\nbeim Storno eines UV07-Nachweises nach erneutem Eintritt im selben Kalenderjahr.\n\nDie Beitragsabrechnung-UV wird neu erzeugt und **zusätzlich** archiviert; die bisherigen\nFassungen bleiben unverändert erhalten.\n",
    "operationId": "uvLohnnachweisKorrektur",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "meldejahr"
        ],
        "properties": {
         "meldejahr": {
          "type": "integer",
          "example": 2026
         },
         "ohne_neumeldung": {
          "type": "boolean",
          "default": false
         },
         "anlass": {
          "type": "string",
          "description": "Klartext für die Ablage."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Nichts zu tun — `grund` nennt warum (keine stornorelevante Änderung, nur Stunden, kein übermittelter Nachweis) oder `huerden` warum es nicht ging"
     },
     "201": {
      "description": "Storno (und ggf. Neumeldung) als Entwurf angelegt"
     },
     "422": {
      "description": "Meldejahr fehlt oder der Vorgang ist nicht durchführbar"
     }
    }
   }
  },
  "/mandanten/{mandantId}/uv-traeger": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "UV-Träger des Mandanten (mehrere möglich, mit Gültigkeitszeiträumen)",
    "operationId": "uvTraegerListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "description": "Ein Unternehmen kann bei mehreren Unfallversicherungsträgern Mitglied sein und bei einem Träger mehrere Unternehmensnummern führen — parallel wie zeitlich anschließend (Pflichtenheft Unfallversicherung 0115, S. 380). Die PIN wird nie ausgeliefert.\n",
    "parameters": [
     {
      "name": "jahr",
      "in": "query",
      "schema": {
       "type": "integer"
      },
      "description": "nur die in diesem Meldejahr gültigen"
     }
    ],
    "responses": {
     "200": {
      "description": "Liste",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "uv_traeger": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/UvTraeger"
           }
          }
         }
        }
       }
      }
     }
    }
   },
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "UV-Träger anlegen oder ändern",
    "operationId": "uvTraegerSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "description": "Die Unternehmensnummer wird über die Prüfziffer an Stelle 12 (Faktoren 4,9,4,9,… modulo 10) und den Suffix (Stellen 13–15, nicht „000\") geprüft; die PIN muss fünfstellig numerisch sein. Überschneidende Zeiträume derselben Nummer beim selben Träger werden abgewiesen.\n",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "bbnr_uv",
         "unternehmensnummer",
         "gueltig_ab"
        ],
        "properties": {
         "id": {
          "type": "integer",
          "description": "zum Ändern eines bestehenden Satzes"
         },
         "bbnr_uv": {
          "type": "string",
          "description": "BBNRUV",
          "achtstellig": null
         },
         "unternehmensnummer": {
          "type": "string",
          "description": "UNR.S",
          "15 Ziffern": null
         },
         "pin": {
          "type": "string",
          "description": "5-stellig numerisch; wird nie zurückgegeben"
         },
         "gueltig_ab": {
          "type": "string",
          "format": "date"
         },
         "gueltig_bis": {
          "type": "string",
          "format": "date",
          "nullable": true
         },
         "notiz": {
          "type": "string",
          "nullable": true
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "gespeichert"
     },
     "422": {
      "description": "Validierung fehlgeschlagen"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{mitarbeiterId}/gefahrtarifstellen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "mitarbeiterId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Gefahrtarifstellen einer Person (mit Anteilen)",
    "operationId": "gefahrtarifstellenLesen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "gefahrtarifstellen": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/MaGefahrtarifstelle"
           }
          }
         }
        }
       }
      }
     }
    }
   },
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Gefahrtarifstellen einer Person setzen (ganze Aufteilung)",
    "operationId": "gefahrtarifstellenSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "description": "Trifft für eine Person mehr als eine Gefahrtarifstelle zu, ist das Entgelt aufzuteilen — auch träger-übergreifend (Pflichtenheft S. 385). Die Anteile müssen zusammen 100 % ergeben; bei mehreren Stellen wird der Anteil nicht geraten. Die Aufteilung wird immer als Ganzes gesetzt, damit nie ein Zwischenstand mit unter 100 % gelesen werden kann.\n",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "gueltig_ab",
         "stellen"
        ],
        "properties": {
         "gueltig_ab": {
          "type": "string",
          "format": "date"
         },
         "gueltig_bis": {
          "type": "string",
          "format": "date",
          "nullable": true
         },
         "stellen": {
          "type": "array",
          "minItems": 1,
          "items": {
           "type": "object",
           "required": [
            "bbnr_uv",
            "gefahrtarifstelle"
           ],
           "properties": {
            "bbnr_uv": {
             "type": "string"
            },
            "gefahrtarifstelle": {
             "type": "string"
            },
            "anteil_prozent": {
             "type": "number",
             "description": "Pflicht",
             "sobald mehr als eine Stelle angegeben ist": null
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "gespeichert"
     },
     "404": {
      "description": "Mitarbeiter nicht gefunden"
     },
     "422": {
      "description": "Validierung fehlgeschlagen"
     }
    }
   }
  },
  "/mandanten/{mandantId}/uv-stammdaten": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "UV-Stammdaten je Meldejahr",
    "operationId": "uvStammdatenListe",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste"
     }
    }
   }
  },
  "/mandanten/{mandantId}/uv-stammdaten/{meldejahr}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "meldejahr",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "put": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Gefahrtarifstellen pflegen",
    "description": "Neukunden-Blocker: ohne Gefahrtarifstelle kein Lohnnachweis. Sie steht **nicht** im\nZugangsdaten-Anschreiben der Berufsgenossenschaft, sondern im Veranlagungsbescheid nach\n§ 159 Abs. 1 SGB VII — sie wird deshalb gepflegt, nicht geraten.\n",
    "operationId": "uvStammdatenSetzen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Gespeichert"
     }
    }
   }
  },
  "/mandanten/{mandantId}/betriebsdaten/vorschau": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "DSBD-Vorschau — was aus diesen Betriebsdaten gemeldet würde (speichert nichts)",
    "description": "Pflichtenheft S. 142: vor der Generierung des DSBD kann der Anwender die Inhalte kontrollieren (a5b0d83f); ergibt eine\nÄnderung der Betriebsdaten einen Plausibilitätshinweis, speichert `PATCH /mandanten/{id}` erst nach Bejahen\n(`betriebsdaten_bestaetigt: true`) — sonst 409 `PLAUSIBILISIERUNG` mit `hinweise` und `vorschau` (c12fc154).\nBody: `aenderungen` (Mandantenfelder, optional), `grund` (`05`|`06`, optional — sonst aus der Änderung abgeleitet), `datum_ereignis`.\n",
    "operationId": "dsbdVorschau",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "aenderungen": {
          "type": "object"
         },
         "grund": {
          "type": "string",
          "enum": [
           "05",
           "06"
          ]
         },
         "datum_ereignis": {
          "type": "string",
          "format": "date"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Vorschau: grund, meldepflichtig, betriebsdaten, aenderungen, hinweise, huerden, annahmestelle_bbnr."
     }
    }
   }
  },
  "/mandanten/{mandantId}/betriebsdaten/aktueller-stand": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "DSBD „Aktueller Stand Betriebsdaten\" (Grund 05) anstoßen",
    "description": "Pflichtenheft S. 142: Grund 05 darf **nur aktiv vom Anwender** im Einzelfall ausgelöst werden —\ndie Betriebsautomatik erzeugt ihn nie. Der Satz trägt alle aktuellen Betriebsdaten ohne\nÄnderungs-Kennzeichen. Das Ereignisdatum ist **nicht vorbelegt** (S. 145) und muss mitgegeben werden.\n",
    "operationId": "dsbdAktuellerStand",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "datum_ereignis"
        ],
        "properties": {
         "datum_ereignis": {
          "type": "string",
          "format": "date",
          "description": "Tag",
          "auf den sich der Stand bezieht (Anwendereingabe)": null
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "DSBD-Entwurf angelegt (gesendet wird nie automatisch)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "grund": {
           "type": "string",
           "enum": [
            "01",
            "05",
            "06"
           ]
          },
          "status": {
           "type": "string",
           "enum": [
            "entwurf"
           ]
          },
          "hinweise": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "422": {
      "description": "Hürde oder fehlende Eingabe (z. B. Ereignisdatum nicht eingegeben)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/betriebsdaten/neuer-dienstleister": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "DSBD „Neuer Dienstleister / Neue Abrechnungssoftware\" (Grund 06)",
    "description": "Pflichtenheft S. 142: bei der erstmaligen Erfassung der Betriebsnummer kennzeichnet der Anwender,\nob ein Systemwechsel oder Dienstleisterwechsel vorliegt. Bejaht er das, entsteht der DSBD mit Grund 06.\nOhne `systemwechsel: true` entsteht nichts.\n",
    "operationId": "dsbdNeuerDienstleister",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "datum_ereignis",
         "systemwechsel"
        ],
        "properties": {
         "datum_ereignis": {
          "type": "string",
          "format": "date",
          "description": "Tag der Übernahme (Anwendereingabe)"
         },
         "systemwechsel": {
          "type": "boolean",
          "description": "Der Anwender bejaht Systemwechsel/Dienstleisterwechsel"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "DSBD-Entwurf angelegt (gesendet wird nie automatisch)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "grund": {
           "type": "string",
           "enum": [
            "01",
            "05",
            "06"
           ]
          },
          "status": {
           "type": "string",
           "enum": [
            "entwurf"
           ]
          },
          "hinweise": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "422": {
      "description": "Hürde oder fehlende Eingabe (z. B. Ereignisdatum nicht eingegeben)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/betriebsdaten/berichtigen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Bereits übermittelten DSBD berichtigen",
    "description": "Pflichtenheft S. 146: sind übermittelte Angaben zu korrigieren, entsteht ein **weiterer** DSBD mit\nden korrekten (aktuellen) Angaben; `DATUM-EREIGNIS` ist gleich dem Wert des zu korrigierenden DSBD.\nKein Storno.\n",
    "operationId": "dsbdBerichtigen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "meldung_id"
        ],
        "properties": {
         "meldung_id": {
          "type": "integer",
          "description": "ID des zu korrigierenden DSBD in lohn_meldungen"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "DSBD-Entwurf angelegt (gesendet wird nie automatisch)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "integer"
          },
          "grund": {
           "type": "string",
           "enum": [
            "01",
            "05",
            "06"
           ]
          },
          "status": {
           "type": "string",
           "enum": [
            "entwurf"
           ]
          },
          "hinweise": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "422": {
      "description": "Hürde oder fehlende Eingabe (z. B. Ereignisdatum nicht eingegeben)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/uv/hoechst-jav": {
   "get": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Höchstjahresarbeitsverdienst je UV-Träger und Jahr (Liste)",
    "description": "Partnerweiter Stammdatensatz (lohn_uv_hoechst_jav). Ohne Wert deckelt der elektronische Lohnnachweis das UV-Entgelt nicht und nennt das im Hinweis.",
    "operationId": "uvHoechstJavListe",
    "x-scope": "partner:mandanten",
    "x-baustand": "verfuegbar",
    "parameters": [
     {
      "name": "jahr",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Werte",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "werte": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "bbnr_uv": {
              "type": "string"
             },
             "jahr": {
              "type": "integer"
             },
             "betrag_cent": {
              "type": "integer"
             },
             "quelle": {
              "type": "string",
              "enum": [
               "stammdatendienst",
               "satzung_manuell"
              ]
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   },
   "put": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Höchstjahresarbeitsverdienst je UV-Träger und Jahr setzen",
    "description": "Die **Schreibstelle** für den Höchst-JAV (bis 22.08.2026 gab es keine — die Tabelle wurde gelesen, nie\ngefüllt). Wert aus der Satzung des Trägers oder dem Stammdatendienst; `quelle` ist Pflicht, geschätzt wird\nnicht. Je Träger und Jahr genau ein Wert (erneutes Setzen ersetzt).\n",
    "operationId": "uvHoechstJavSetzen",
    "x-scope": "partner:mandanten",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "bbnr_uv",
         "jahr",
         "betrag_cent",
         "quelle"
        ],
        "properties": {
         "bbnr_uv": {
          "type": "string",
          "description": "achtstellige Betriebsnummer des UV-Trägers"
         },
         "jahr": {
          "type": "integer"
         },
         "betrag_cent": {
          "type": "integer"
         },
         "quelle": {
          "type": "string",
          "enum": [
           "stammdatendienst",
           "satzung_manuell"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Gesetzt"
     },
     "422": {
      "description": "Ungültige Eingabe",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/zuruecksetzen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Sandbox-Mandanten auf Anfang stellen",
    "description": "**Nur in der Sandbox.** Auf einem produktiven Mandanten antwortet der Endpunkt\n`403 NUR_SANDBOX` — ein Zurücksetzen würde dort festgeschriebene Entgeltabrechnungen\nlöschen, für die eine Aufbewahrungspflicht besteht.\n\nGelöscht werden die **beweglichen** Daten: Läufe, Abrechnungen, Meldungen, Dokumente,\nBewegungsdaten, Posteingang, Webhook-Zustellungen. Es **bleiben** die Stammdaten —\nMandant, Mitarbeiter, Zeitscheiben, Bankverbindung, Fehlzeiten, Schlüssel. Ein\nVollabriss würde nach jedem Versuch ein neues Seeding erzwingen; das wäre keine\nErleichterung, sondern eine zweite Hürde.\n\nDie Antwort nennt je Tabelle die Anzahl gelöschter Zeilen und unter `dateien`, wie viele\nabgelegte Dokumente mitgelöscht wurden. Erscheint\n`unbekannte_tabellen`, ist eine Fachtabelle hinzugekommen, die der Reset noch nicht\nkennt — dann ist der Mandant **nicht vollständig** zurückgesetzt.\n",
    "operationId": "mandantZuruecksetzen",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Zurückgesetzt"
     },
     "403": {
      "description": "Kein Sandbox-Mandant (`NUR_SANDBOX`)"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/versicherungsnummer/rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Rückmeldung der DSRV zur Versicherungsnummer übernehmen",
    "description": "Die Gegenrichtung zur Versicherungsnummernabfrage (`POST /meldungen` mit\n`verfahren: dsvv`). Body: `sv_nummer`, oder `mehrdeutig: true`, oder `gefunden: false`.\n\n⚠️ **Eine vorhandene Nummer wird nie überschrieben.** Meldet die Rentenversicherung eine\nandere als die hinterlegte, bleibt die hinterlegte stehen und der Widerspruch landet\nsichtbar im Posteingang — ein stiller Wechsel änderte die Identität der Person in allen\nkünftigen Meldungen.\n\n⚠️ Die zurückgemeldete Nummer wird **geprüft** (Prüfziffer, Geburtsdatum), bevor sie in\nden Stammsatz geht. Besteht sie die Prüfung nicht, wird sie nicht übernommen.\n\n`mehrdeutig` und „nicht gefunden\" sind **Zustände, keine Fehler**: beide werden abgelegt,\ndamit jemand die Abfrage mit genaueren Angaben wiederholt.\n",
    "operationId": "vsnrRueckmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — `uebernommen` sagt, ob der Stammsatz sich geändert hat."
     },
     "422": {
      "description": "Die Rückmeldung trifft keine Aussage"
     }
    }
   }
  },
  "/mandanten/{mandantId}/eubp/rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Rückmeldung des Rentenversicherungsträgers zur euBP übernehmen",
    "description": "Body: `art` (`dssm` | `dsum` | `dsgm` | `pruefergebnis` | `protokoll`), optional\n`meldung_id`, `status` (bei DSSM) und `pdf_base64` (beim Prüfbescheid).\n\n⚠️ **DSUM und DSGM sind MELDEVORSCHLÄGE, keine fertigen Meldungen.** Der Prüfer schlägt\neine Korrektur vor; abgeben darf sie nur der Arbeitgeber. Sie landen als Vorschlag im\nPosteingang und werden nie automatisch gesendet — wer das täte, meldete der Einzugsstelle\ndie Rechtsauffassung eines Dritten unter eigenem Namen.\n\n⚠️ Die Statusmeldung **E90** friert die Prüfung ein: danach ist zu diesem Termin nichts\nmehr zu liefern. Der Status wird auf der Lieferung vermerkt, und `POST /eubp` liest ihn\ndort wieder.\n\nDer Prüfbescheid kommt als PDF und wird **separat speicherbar** abgelegt — er ist ein\nDokument für den Arbeitgeber, kein Datenfeld, aus dem etwas zu rechnen wäre.\n",
    "operationId": "eubpRueckmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — `handlungsbedarf` sagt, ob jemand hinsehen muss."
     },
     "422": {
      "description": "Unbekannte Art"
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen/{meldungId}/verarbeitungsprotokoll": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "meldungId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Verarbeitungsprotokoll der Annahmestelle übernehmen (Block 4, Rückrichtung)",
    "description": "Body: `roh` — der zurückgesendete Datensatz als Text.\n\nNach dem Senden liefert die Annahmestelle **unseren eigenen Datensatz** mit gesetztem\nFehlerkennzeichen zurück: `FEKZ` an Position 61, `FEAN` (Anzahl der Fehlerbausteine) an 62,\ndanach bis zu neun `DBFE`-Bausteine à 87 Zeichen. Die Feldlagen sind aus dem amtlichen\nDEÜV-Kernprüfprogramm belegt.\n\n| FEKZ | Bedeutung | Status |\n|---|---|---|\n| `0` | fehlerfrei | `bestaetigt` |\n| `1` | Fehler | `fehler` |\n| `3` | **nur Hinweise** | `bestaetigt` |\n\n⚠️ **`3` ist ein Hinweis, keine Ablehnung.** Wer ihn als Fehler behandelt, sendet eine\nbereits angenommene Meldung ein zweites Mal.\n\n⚠️ **Zugeordnet wird über die Meldung, nicht über den Inhalt.** Welcher Datensatz\nzurückkam, weiß nur der Aufrufer — aus dem Satz zu raten hieße, eine fremde Rückmeldung der\nfalschen Meldung zuzuordnen und deren Status still zu fälschen.\n\nDer Fehlertext geht im **Klartext** in den Posteingang: „DSME010\" allein sagt niemandem\netwas.\n",
    "operationId": "verarbeitungsprotokoll",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verbucht — `status` und `fehler` sagen, was die Annahmestelle meldet."
     },
     "404": {
      "description": "Meldung nicht bei diesem Mandanten"
     },
     "422": {
      "description": "roh fehlt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/transport/dateinummern": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "x-scope": "mandant:meldungen",
    "summary": "Dateifolgenummern des Vorlaufsatzes anzeigen",
    "description": "Jede Übertragungsdatei trägt im Vorlaufsatz eine sechsstellige laufende Nummer. Sie wird\nautomatisch verwaltet — je **Absender, Empfänger und Verfahren**, denn dieselbe\nBetriebsnummer kann an mehrere Annahmestellen senden, und jede führt ihre eigene Folge.\n",
    "responses": {
     "200": {
      "description": "Zählerstände",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "dateinummern": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "absender_bbnr": {
              "type": "string"
             },
             "empfaenger_bbnr": {
              "type": "string"
             },
             "verfahren": {
              "type": "string"
             },
             "stand": {
              "type": "integer",
              "description": "zuletzt VERBRAUCHTE Nummer"
             },
             "gesetzt_von": {
              "type": "string",
              "nullable": true
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   },
   "put": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "x-scope": "mandant:meldungen",
    "summary": "Dateifolgenummer setzen (nach einer Störung)",
    "description": "„Die Dateinummer wird automatisch verwaltet, **kann jedoch durch den Anwender editiert\nwerden**\" (Pflichtenheft S. 119). Nach einer Störung erwartet die Annahmestelle eine\nbestimmte Nummer — dann setzt der Anwender sie hier.\n\n⚠️ Gesetzt wird der **Stand**, also die zuletzt verbrauchte Nummer: die nächste Datei\nträgt `stand + 1`. Die Antwort nennt sie ausdrücklich.\n",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "verfahren",
         "empfaenger_bbnr",
         "stand"
        ],
        "properties": {
         "verfahren": {
          "type": "string",
          "example": "deuev"
         },
         "empfaenger_bbnr": {
          "type": "string",
          "example": "66667777"
         },
         "stand": {
          "type": "integer",
          "minimum": 1,
          "maximum": 999999
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "gesetzt",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "stand": {
           "type": "integer"
          },
          "naechste_datei": {
           "type": "integer"
          },
          "hinweis": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "422": {
      "$ref": "#/components/responses/Validierung"
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen/versand": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "🔒 Geprüfte und freigegebene SV-Meldungen an die Datenannahmestellen senden",
    "description": "**Der** Aufrufer des Versands (Schlachtplan N5). Es gibt vier Tore, und dieser Endpunkt\nöffnet keines davon:\n\n1. Betriebs-Riegel `VERSAND_FREIGEGEBEN=1` in der Umgebung des Servers — standardmäßig ZU,\n   nur die Geschäftsführung setzt ihn.\n2. Kein Sandbox-Mandant.\n3. Transport konfiguriert (`SV_KOMSERVER_URL`, `SV_P12_PFAD`/`SV_P12_PIN`, `SV_EMPFAENGER_ZERT_PFAD`)\n   — Zertifikat und Zugang kommen mit der ITSG-Zulassung.\n4. Jede Meldung hat Status `geprueft` **und** ist durch einen Menschen freigegeben\n   (`POST …/meldungen/{meldungId}/freigabe`).\n\nEin geschlossenes Tor antwortet **423** mit dem Grund (`VERSAND_GESPERRT`, `SANDBOX_KEIN_VERSAND`,\n`TRANSPORT_NICHT_KONFIGURIERT`) und sendet nichts. `nur_zeigen: true` zeigt Tore und Stand,\nohne zu senden. Nach erfolgreichem Versand entstehen zu den gesendeten DEÜV-Meldungen die\nBescheinigungen nach § 28a Abs. 5 SGB IV. Runbook: `docs/sv_versand_runbook.md`.\n",
    "operationId": "meldungenVersenden",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "zertifizierung",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "akteur": {
          "type": "string",
          "description": "Name des Menschen",
          "der den Versand auslöst (sonst der Schlüsselinhaber)": null
         },
         "nur_zeigen": {
          "type": "boolean",
          "description": "Nur Tore und Stand zeigen",
          "nichts senden": null
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Nur gezeigt (nur_zeigen)"
     },
     "201": {
      "description": "Gesendet",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "versandt": {
           "type": "integer"
          },
          "ids": {
           "type": "array",
           "items": {
            "type": "integer"
           }
          },
          "pakete": {
           "type": "integer"
          },
          "bescheinigungen": {
           "type": [
            "object",
            "null"
           ]
          }
         }
        }
       }
      }
     },
     "409": {
      "description": "Versand abgebrochen (keine Freigabe, kein Zertifikat, kein Endpunkt, Annahmestelle …)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     },
     "423": {
      "description": "Ein Tor ist geschlossen — nichts gesendet",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen/{meldungId}/freigabe": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "meldungId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "🔒 Eine Meldung zur Übermittlung freigeben",
    "description": "Body: `akteur` (Pflicht — der Name des Menschen, der freigibt) und `bestaetigung`, die das\n**Verfahren** der Meldung wiederholen muss.\n\n🔒 **Aus Lohnfluss geht nichts an eine Behörde oder Kasse hinaus, bevor es ausdrücklich\nfreigegeben wurde.** Es gibt **zwei unabhängige Tore**, und eines allein genügt nie:\n\n1. Der **Betriebs-Riegel** `VERSAND_FREIGEGEBEN=1` in der Umgebung — standardmäßig ZU.\n2. Die **Freigabe je Meldung** über diesen Weg.\n\n⚠️ **Auch eine Testübermittlung ist gesperrt.** Der Testmerker macht sie *fachlich* zum\nTest; *technisch* ist es eine echte Verbindung zu einem Behördenserver, mit echten\nPersonen- und Entgeltdaten im Umschlag.\n\n⚠️ **Es gibt kein „alles freigeben\".** Eine Sammel-Freigabe wäre praktisch dasselbe wie\nkein Tor. Und eine Freigabe ohne Namen wird abgewiesen: in der Betriebsprüfung ist „wer hat\ndas abgegeben?\" die erste Frage.\n",
    "operationId": "meldungFreigeben",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Freigegeben"
     },
     "404": {
      "description": "Meldung nicht bei diesem Mandanten"
     },
     "422": {
      "description": "Akteur fehlt oder die Bestätigung passt nicht zum Verfahren"
     }
    }
   },
   "delete": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "🔒 Eine Freigabe zurücknehmen",
    "description": "Möglich, solange nichts gesendet wurde.\n",
    "operationId": "freigabeZuruecknehmen",
    "x-scope": "mandant:lohnlauf",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Zurückgenommen"
     },
     "409": {
      "description": "Keine offene Freigabe — oder bereits gesendet"
     }
    }
   }
  },
  "/mandanten/{mandantId}/traeger-anforderungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Eingehende Anforderung eines Trägers annehmen (vier Anlässe)",
    "description": "Body: `typ` (`arbeitgeberkonto` | `fehlende_jahresmeldung` | `gesonderte_meldung` |\n`mitgliedsbestaetigung`), dazu `sv_nummer`, `kasse_ik`, `zeitraum` je nach Anlass.\n\n⚠️ **Nicht zu verwechseln mit `POST /anforderungen`** — jener Weg nimmt rvBEA-FORMS und\nGML57 an, die eine *Bescheinigung* verlangen. Hier hat jeder Anlass eine eigene Handlung.\n\n⚠️ **Die Gesonderte Meldung ist NACHRANGIG** — die Regel, die man ohne den Text umgekehrt\nbaut: „Entgeltmeldungen aufgrund anderer meldepflichtiger Tatbestände gehen einer\nGesonderten Meldung grundsätzlich vor. Einzige Ausnahme stellt die Jahresmeldung dar.\"\nDeckt eine andere Meldung den Zeitraum ab, unterbleibt sie — und der Fall bekommt trotzdem\nein Fehler-Kennzeichen, denn der Träger erwartet eine Antwort.\n\n⚠️ **Der Abgabezeitpunkt** hängt daran, ob der Zeitraum schon abgerechnet ist: mit der\nAbrechnung des letzten Monats des angeforderten Zeitraums, sonst mit der nächsten. Wer\nimmer sofort meldet, meldet ein Entgelt, das noch nicht feststeht.\n\nZugeordnet wird über die **Versicherungsnummer**, nie über den Namen: eine falsch\nzugeordnete Anforderung erzeugte eine Meldung über die falsche Person.\n",
    "operationId": "traegerAnforderung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Angenommen — mit Aktion, Zuordnung und Posteingangs-Eintrag."
     },
     "422": {
      "description": "Unbekannter Anforderungstyp"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/kassenabruf": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Zuständige Krankenkasse beim GKV-Spitzenverband abrufen",
    "description": "Body: `anlass` (`keine_angabe` | `zmv_unzustaendig` | `mitgliedsbestaetigung` |\n`eau_unzustaendig`), bei `keine_angabe` zusätzlich `beschaeftigter_aufgefordert`.\n\n⚠️ **Der Abruf ist an eine Voraussetzung gebunden, nicht frei.** Zulässig nur, sofern eine\nMeldung nach § 28a SGB IV ansteht **und** trotz vorheriger Aufforderung des Beschäftigten\nkeine oder unvollständige Angaben vorliegen. Ein Abruf auf Verdacht wäre eine Abfrage von\nSozialdaten ohne Grundlage — er wird mit 422 abgewiesen.\n\n⚠️ `angaben_vollstaendig` wird **gemessen**, nicht übernommen: liegt an der Zeitscheibe\neine Kasse, ist der Abruf beim Anlass „keine Angabe\" unzulässig. Meldet sich dagegen eine\nKasse selbst als unzuständig, ist die hinterlegte ja gerade die falsche — dann entfällt\nauch das Nachfragen beim Beschäftigten.\n\n⚠️ Die Anfrage geht an den **Spitzenverband** (BBNR 93121302), nicht an eine Krankenkasse:\ner sucht über alle hinweg.\n",
    "operationId": "kassenabruf",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Abruf als Entwurf angelegt"
     },
     "422": {
      "description": "Der Abruf ist nicht zulässig — siehe `huerden`."
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/kassenabruf/rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Rückmeldung des GKV-Spitzenverbandes übernehmen",
    "description": "Body: `ergebnis` (`1` = Mitgliedschaft ermittelt, `2` = keine), bei `1` zusätzlich\n`bbnr_kk`.\n\nBei `1` wandert die Kasse **direkt in die Stammdaten** — genau dafür wurde gefragt; ein\nZwischenschritt „bitte abtippen\" wäre die Fehlerquelle, die das Verfahren beseitigen soll.\n\n⚠️ Bei `2` **endet das Verfahren, es beginnt nicht neu.** Der Arbeitgeber ist zu weiteren\nErmittlungen beim Beschäftigten verpflichtet; ein zweiter Abruf brächte dasselbe Ergebnis.\nDer Fall landet mit Handlungsbedarf im Posteingang.\n",
    "operationId": "kassenabrufRueckmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — `uebernommen` sagt, ob der Stammsatz sich geändert hat."
     },
     "422": {
      "description": "ergebnis ist weder 1 noch 2"
     }
    }
   }
  },
  "/mandanten/{mandantId}/unbedenklichkeit": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Unbedenklichkeitsbescheinigung beantragen (je Einzugsstelle)",
    "description": "Body: `einzugsstellen` (Liste aus `{kasse_bbnr, bezug}`; Bezug `einmalig` | `monatlich` |\n`vierteljaehrlich` | `halbjaehrlich`), optional `durch_bevollmaechtigten`,\n`vollmacht_pdf`, `auch_englisch`.\n\nDie Bescheinigung bestätigt, dass Beiträge ordnungsgemäß abgeführt wurden. Gebraucht wird\nsie für **Dritte**: Auftraggeber bei Vergaben, Generalunternehmer bei Nachunternehmern,\nBanken bei Krediten.\n\n⚠️ **Der Bezug wird JE EINZUGSSTELLE gewählt.** Ein Arbeitgeber mit Beschäftigten bei fünf\nKassen kann bei der einen monatlich abonnieren und bei der anderen einmalig beantragen.\n\n⚠️ **Ohne hinterlegte Vollmacht darf ein Bevollmächtigter nicht abrufen** — die Kasse gäbe\nsonst Beitragsdaten an einen Dritten. Das Kennzeichen allein reicht nicht.\n",
    "operationId": "unbedenklichkeitBeantragen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Anträge als Entwürfe angelegt",
      "Abonnements geführt": null
     },
     "422": {
      "description": "Unbekannte Bezugsart oder fehlende Vollmacht — siehe `huerden`."
     }
    }
   }
  },
  "/mandanten/{mandantId}/unbedenklichkeit/{kasseBbnr}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "kasseBbnr",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string"
     }
    }
   ],
   "delete": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Abonnement bei EINER Einzugsstelle widerrufen",
    "description": "⚠️ Der Widerruf gilt **je Einzugsstelle**, wie das Abonnement selbst. Ein „alles\nabbestellen\" gibt es im Verfahren nicht — ein selbstgebautes beendete stillschweigend\nAbos, die der Anwender behalten wollte.\n\nEin widerrufenes Abonnement fällt auf „kein Abo\" zurück; die einmalige Anforderung bleibt\njederzeit möglich.\n",
    "operationId": "unbedenklichkeitWiderrufen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Widerrufen"
     },
     "404": {
      "description": "Kein Abonnement bei dieser Einzugsstelle"
     }
    }
   }
  },
  "/mandanten/{mandantId}/unbedenklichkeit/rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Rückmeldung der Einzugsstelle übernehmen",
    "description": "Body: `kasse_bbnr` (Pflicht), `pdf_base64` **oder** `ablehnungsgrund`, optional `monat`\n(`jjjj-mm`).\n\n⚠️ Die Bescheinigung kommt als **eingebettetes PDF**, nicht als Datenfeld. Sie wird\nabgelegt und bereitgestellt — anzeigbar und druckbar. Werte daraus zu extrahieren wäre am\nZweck vorbei.\n\nLäuft ein Abonnement, wird daraus der **nächste Termin** bestimmt und geführt. Eine\nAblehnung landet mit Handlungsbedarf im Posteingang: sie heißt, dass die Kasse Rückstände\nsieht.\n",
    "operationId": "unbedenklichkeitRueckmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — mit `dokument_id` und `naechster_termin`."
     },
     "422": {
      "description": "kasse_bbnr fehlt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/dxbd": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Dialogverfahren Betriebsdatenpflege — DXBD anlegen",
    "description": "Body: `erstmalig` | `beendigung` | `manuell` | `vorher` (Stand vor der Änderung), optional\n`bbnr`, `bestaetigt` (beantwortete Rückfragen), `negativliste`, `signalwoerter`,\n`rechtsform_plausibilisierbar` / `rechtsform_passt`.\n\n⚠️ **Nicht der DSBD.** Der geht als Byte-Satz an die Betriebsnummern-Datei der\nRentenversicherung — eine Einbahnstraße. Dies hier ist ein **Dialog mit der Bundesagentur**:\nauf jeden DXBD antwortet ein DXBE, und die Antwort kann eine Prüfaufforderung sein.\n\n⚠️ **Ein offener Vorgang blockiert.** Ein neuer A01/A02 darf erst entstehen, wenn der\nvorige durch B01/B02/B06 abgeschlossen ist. Wer das nicht führt, schickt der BA zwei\nkonkurrierende Änderungen desselben Betriebs, und welche gewinnt, entscheidet die\nReihenfolge des Eingangs dort.\n\n⚠️ **Rückfragen sind Pflicht, keine Empfehlung.** Bleiben sie offen, entsteht keine\nMeldung — die BA weist unplausible Stammdaten zurück, und jede Zurückweisung ist ein\nweiterer Dialogschritt. `negativliste` und `signalwoerter` kommen von der BA und werden\ndurchgereicht, nicht erfunden.\n\nAntwortet mit **200 und `ok: false`**, wenn kein Anlass besteht oder Rückfragen offen sind\n— beides sind Zustände, keine Fehleingaben.\n",
    "operationId": "dxbdAnlegen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Kein Anlass oder offene Rückfragen — siehe `rueckfragen`/`huerden`."
     },
     "201": {
      "description": "Entwurf angelegt, Vorgang eröffnet."
     }
    }
   }
  },
  "/mandanten/{mandantId}/dxbd/wukl-abfrage": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Wirtschaftsunterklasse abfragen (DXBD A05)",
    "description": "Fragt die Wirtschaftsunterklasse (WUKL) aus dem Dateisystem der Beschäftigungsbetriebe\nab. Body: optional `bbnr` (sonst die Betriebsnummer des Mandanten).\n\n⚠️ **A05 trägt AUSSCHLIESSLICH Mussfelder** — keine Betriebsdaten, kein Ereignisdatum:\n„auch bedingte Mussfelder (m) dürfen nicht übertragen werden, unabhängig davon, ob die\nentsprechende Information vorliegt\".\n\n⚠️ **Die Abfrage eröffnet KEINEN Vorgang.** Die Antwort darauf ist ein B05 „Hinweis\", und\nder schließt keinen Vorgang — ein Vorgang bliebe für immer offen und sperrte jede künftige\nBestands- oder Änderungsmeldung dieses Betriebs.\n\n⚠️ Die zurückgemeldete WUKL wird **nicht selbsttätig** in die Stammdaten übernommen: sie\nist ein gemeldetes Stammdatum, und ein Wert, der ohne Zutun des Anwenders in den Stamm\nwandert, löste beim nächsten Änderungsvergleich ein A02 aus, das niemand veranlasst hat.\n",
    "operationId": "dxbdWuklAbfrage",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Nicht erzeugt — siehe `huerden` (gesperrter Nummernkreis, Beendigung übermittelt)."
     },
     "201": {
      "description": "Entwurf A05 angelegt."
     }
    }
   }
  },
  "/mandanten/{mandantId}/dxbd/antwort": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Antwort der Bundesagentur (DXBE) übernehmen",
    "description": "Body: `abgabegrund` (B01–B06), optional `datensatz_id`, `fehler` (Liste aus\n`{nummer, hinweis}`), `bbnr`.\n\n⚠️ **B03/B04 schließen den Vorgang NICHT.** Sie sind Prüfaufforderungen und verlangen ein\nA06 „Prüfergebnis\". Wer sie als Abschluss behandelt, hält den Betrieb für gemeldet, während\ndie BA noch wartet.\n\n⚠️ Dem Anwender wird der **BA_Fehlerhinweis** angezeigt, nicht die Fehlernummer — „F0001\"\nsagt niemandem etwas.\n",
    "operationId": "dxbdAntwort",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — `folgemeldung` nennt ein fälliges A06."
     },
     "422": {
      "description": "abgabegrund ist kein B01–B06"
     }
    }
   }
  },
  "/mandanten/{mandantId}/dxbd/{vorgangId}/pruefergebnis": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "vorgangId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Prüfergebnis (A06) zu einer Prüfaufforderung abgeben",
    "description": "Body: `entscheidungen` — je gemeldeter Fehlernummer `korrigiert` oder `bestaetigt`; dazu\n`ereignisdatum` (jjjjmmtt, **Pflicht, nie vorbelegt** — Eingabe des Anwenders).\n\n⚠️ **Zu JEDER gemeldeten Fehlernummer gehört eine Prüfbestätigung** — auch dort, wo der\nAnwender nichts geändert, sondern die Richtigkeit bestätigt hat. Eine Lücke wird mit 422\nabgewiesen und nennt die fehlende Nummer: ein A06 mit Lücke ließe den Vorgang offen und\nblockierte jede weitere Änderungsmeldung dieses Betriebs, ohne dass etwas rot würde.\n\nDas A06 trägt den korrigierten/bestätigten Stand der betrieblichen Stammdaten und die\nReferenz_Id des DXBE; es beantwortet die Prüfaufforderung und schließt den Vorgang.\nDas XML-Wire-Format steht noch aus (docs/dxbd_xml_offen.md) — gespeichert werden die\nNutzdaten nach dem Mussfeld-Schnitt.\n",
    "operationId": "dxbdPruefergebnis",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Prüfergebnis angelegt",
      "Vorgang geschlossen": null
     },
     "422": {
      "description": "Lücke im Prüfergebnis, Ereignisdatum fehlt oder keine Prüfaufforderung vorhanden"
     }
    }
   }
  },
  "/mandanten/{mandantId}/dxbd/{vorgangId}/unzustaendigkeit": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "vorgangId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Unzuständigkeitserklärung (A04) zu einer Prüfaufforderung abgeben",
    "description": "Body optional: `begruendung` (wird vermerkt, nicht übertragen).\n\nAntwort auf einen DXBE (B03/B04), für dessen Betrieb dieser Mandant nicht zuständig ist.\nDas A04 trägt die Datensatz_Id des DXBE als Referenz_Id und keine betrieblichen Stammdaten;\nes schließt den Vorgang. Ohne Referenz-ID (kein DXBE zum Vorgang) 422.\n",
    "operationId": "dxbdUnzustaendigkeit",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "A04 angelegt",
      "Vorgang geschlossen": null
     },
     "404": {
      "description": "Vorgang nicht bei diesem Mandanten"
     },
     "422": {
      "description": "keine Referenz-ID oder Vorgang nicht offen"
     }
    }
   }
  },
  "/mandanten/{mandantId}/dxbd/beendigung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Vollständige Beendigung der Betriebstätigkeit melden (A03)",
    "description": "Body: `beendet_am` (jjjj-mm-tt — der Tag der vollständigen Einstellung, **Eingabe des\nAnwenders, nie vorbelegt**), optional `bestaetigt` (beantwortete Rückfragen).\n\n⚠️ Vorher stehen die Rückfragen — Mechanismus B des Pflichtenhefts: sind auf der\nBetriebsnummer noch nicht beendete Beschäftigungsverhältnisse, kommt der Hinweis, die\nPersonen zuerst umzuhängen oder abzumelden. Bleiben Rückfragen offen, wird **nichts**\ngeschrieben (200, `ok: false`). Entsteht der A03, wandert das Datum als\n`betrieb_beendet_am` in den Mandantenstamm (Migration 086) — danach ist zu dieser\nBetriebsnummer kein weiterer DXBD möglich.\n",
    "operationId": "dxbdBeendigung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Rückfragen offen oder Datum fehlt — siehe `rueckfragen`/`huerden`."
     },
     "201": {
      "description": "A03 als Entwurf angelegt, Beendigungsdatum gespeichert."
     }
    }
   }
  },
  "/mandanten/{mandantId}/anforderungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Anforderung eines Trägers annehmen (rvBEA-FORMS · GML57)",
    "description": "Body: `anforderung` (der Datensatz), `eingang` (Tag der Quittierung, `jjjjmmtt`), optional\n`feiertage` (Liste `jjjjmmtt`).\n\nDer Rentenversicherungsträger fordert eine Bescheinigung an und kennzeichnet darin die\nFelder und Zeiträume, die er braucht. Dieser Weg ordnet die Anforderung **automatisiert**\neiner Person zu (über AZ-VU, sonst über die Versicherungsnummer), bestimmt die Frist und\nlegt sie im Posteingang ab.\n\n⚠️ **Die Frist ist die kürzeste im ganzen Meldewesen** — im Regelfall **ein Arbeitstag**\nnach der Quittierung. Sie steht in der eigenen Spalte `faellig_am`, damit der Posteingang\ndanach sortiert und Überfälliges oben zeigt.\n\n⚠️ Eine **nicht zuordenbare** Anforderung landet erst recht im Posteingang, zusätzlich mit\nFehler-Kennzeichen: sonst wartet der Träger auf eine Antwort, die niemand erstellt, weil\nniemand von der Anforderung weiß.\n\n⚠️ Die Kandidatenliste für die Zuordnung kommt aus der **Datenbank**, nicht aus dem Body —\nsonst entschiede der Absender, gegen wen zugeordnet wird.\n\nEs wird nichts gesendet: erzeugt wird ein Vorgang, der Versand ist ein eigener Schritt.\n",
    "operationId": "anforderungAnnehmen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Angenommen — mit Zuordnung, Frist und Posteingangs-Eintrag."
     },
     "422": {
      "description": "anforderung oder eingang fehlt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/anforderungen/{posteingangId}/antwort": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "posteingangId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     },
     "description": "Der Posteingangs-Eintrag mit der Anforderung (DXAR)."
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Antwort auf eine rvBEA-Anforderung erzeugen (DXEB)",
    "description": "Erzeugt den Antwortdatensatz zu einer eingegangenen Anforderung des\nRentenversicherungsträgers — mit den in der Anforderung **gekennzeichneten Feldern** und\n**Zeiträumen**.\n\n**Bescheinigt werden die Werte der jeweiligen Monate, wie sie abgerechnet wurden** — nicht\nein neu gerechneter Stand (Pflichtenheft S. 329: „die zum Zeitpunkt der Erstellung des\nAntwortdatensatzes geltenden Werte\"). Je Monat gilt der zuletzt festgeschriebene Lauf.\n\nEin Monat **ohne** Abrechnung bekommt einen Hinderungsgrund; geschätzt wird nichts. Kann\nkein einziger Zeitraum bescheinigt werden, trägt die Antwort einen Grund für das Ganze.\n\n⚠️ Der Entwurf geht **nicht** hinaus — der Versand ist ein eigener, freigegebener Schritt.\nDie Antwortfrist („innerhalb eines Arbeitstages nach Eingang\") steht am\nPosteingangs-Eintrag und wird vom Fristen-Wächter überwacht.\n",
    "operationId": "rvbeaAntwortErzeugen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Antwortdatensatz als Entwurf angelegt.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "meldung": {
           "type": "object"
          },
          "vollstaendig": {
           "type": "boolean",
           "description": "Falsch, wenn ein Zeitraum nicht bescheinigt werden konnte."
          },
          "monate": {
           "type": "integer"
          },
          "ohne_werte": {
           "type": "integer"
          },
          "huerden": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Auth"
     },
     "403": {
      "$ref": "#/components/responses/Scope"
     },
     "409": {
      "description": "Nichts zu bescheinigen — etwa ohne Personenzuordnung oder ohne angeforderte Felder.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Fehler"
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/anforderungen/werteliste": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Maschinelle Rückmeldung `Werteliste_AG` des RV-Trägers annehmen",
    "description": "Body: `meta` (Pflicht) und `fach_daten`. Der Träger meldet zurück, **wer zuständig ist**.\n\n⚠️ Zugeordnet wird **ausschließlich über die mitgelieferten Meta-Daten** — keine Heuristik\nüber Namen oder Zeitpunkte. Eine falsch zugeordnete Rückmeldung hängt an der falschen\nAnforderung und fällt niemandem auf.\n\n⚠️ Der Träger wird **im Klartext** angezeigt, und zwar mit der Bezeichnung **aus der\nRückmeldung**. Kommt nur ein Schlüssel ohne Bezeichnung, wird er unverändert\ndurchgereicht und das benannt — ein eigener Trägerkatalog sähe amtlich aus und wäre es\nnicht.\n\n⚠️ Die Werteliste ist eine **Auskunft, keine Meldung**: kein Entwurf, kein Versand und\n**keine Frist**. Ein Fälligkeitsdatum würde eine Handlungspflicht vortäuschen, die es\nnicht gibt.\n",
    "operationId": "anforderungWerteliste",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Angenommen — `zugeordnet` sagt, ob die Referenz gefunden wurde."
     },
     "422": {
      "description": "meta fehlt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/dabpv/abonnements": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "DaBPV-Abonnements auf Stand bringen (§ 55a SGB XI)",
    "description": "Seit dem 01.07.2023 hängt der PV-Beitrag an der Zahl der Kinder. Der Arbeitgeber darf sie\n**nicht raten** — er fragt sie beim Bundeszentralamt für Steuern ab. Ein Abonnement ist\neine stehende Anfrage: ändert sich die Kinderzahl, kommt die Antwort von selbst.\n\nDieser Weg vergleicht je Beschäftigtem Soll und Ist und legt die nötigen An-/Abmeldungen\nals **Entwürfe** an. Gesendet wird nie automatisch.\n\n⚠️ **„Dem Grunde nach\" ist die Falle des Verfahrens.** Eine Unterbrechung wegen Krankengeld\noder Elternzeit beendet das Abonnement NICHT — die Beitragspflicht besteht fort. Nur\nBeitragsgruppe PV „0\" oder das Ende der Beschäftigung beenden es. Wer bei jeder\nUnterbrechung abmeldet, erzeugt ein Ab-/Anmelde-Paar je Krankengeld-Phase.\n\n⚠️ Ändert sich das **Zuordnungsmerkmal** (ABSN-BBNRAS-HABBNR), bricht das Abonnement: es\ngeht eine Abmeldung UND eine Anmeldung hinaus, die Abmeldung zuerst und an einem anderen\nTag — sonst kann das BZSt die Reihenfolge nicht erkennen.\n\nOhne steuerliche Identifikationsnummer entsteht keine Anfrage; der Fall steht in `huerden`.\n",
    "operationId": "dabpvAbonnements",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Aktionen je Person, erzeugte Entwürfe, Hürden und Hinweise."
     }
    }
   }
  },
  "/mandanten/{mandantId}/dabpv/offen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Für wen fehlt die Auskunft zur Kinderzahl noch?",
    "description": "Die Frage, die **vor** der Abrechnung zu stellen ist.\n\n⚠️ Ohne Rückmeldung und ohne manuelle Angabe wird **nicht „kinderlos\" unterstellt** — das\nwäre der teurere Beitrag, zulasten des Beschäftigten. Deshalb liefert dieser Weg eine\nListe und keine Vermutung.\n",
    "operationId": "dabpvOffen",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste der Personen ohne Auskunft, je mit Grund."
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/dabpv/rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Rückmeldung des BZSt zur Kinderzahl übernehmen",
    "description": "Body: `elterneigenschaft` (boolean) und/oder `kinder` (Liste aus `{ab, anzahl}`), optional\n`stichtag`. Der Weg nimmt sowohl die Antwort auf eine Anfrage als auch die **proaktive**\nRückmeldung entgegen, die ein laufendes Abonnement bei jeder Änderung auslöst.\n\nDie Rückmeldung ist die **autoritative** Quelle für den PV-Beitrag: `pv_kinder` wird\nnachgezogen — aber nur, wenn sich der Wert wirklich ändert, und mit einem Posteingang,\ndamit die Änderung nicht unbemerkt in die nächste Abrechnung läuft. Betroffene Monate sind\ngegebenenfalls aufzurollen.\n\n**Fehlersatz:** statt `elterneigenschaft`/`kinder` kann `fehler` (`{nummer, text}`)\nübergeben werden — ein vom BZSt ZURÜCKGEWIESENER Satz. Er fasst `pv_kinder` nicht an und\nbestätigt kein Abonnement, sondern erzeugt einen Posteingang mit Fehlerkennzeichen: die\nAngaben sind zu berichtigen und die Anfrage zu wiederholen.\n",
    "operationId": "dabpvRueckmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — `uebernommen` sagt, ob der Stammsatz sich geändert hat."
     },
     "422": {
      "description": "Die Rückmeldung trifft keine Aussage"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/dabpv/historienanfrage": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Historienanfrage zur Kinderzahl (mit Bis-Datum)",
    "description": "Body: `ab_datum` und `bis_datum` (`jjjj-mm-tt` oder `jjjjmmtt`) — **beide Pflicht, beide\nohne Vorbelegung**. Die Historienanfrage erfragt einen ZURÜCKLIEGENDEN Zeitraum; sie legt\nkein Abonnement an und beendet keines.\n\nAmtliche Grenzen (Pflichtenheft S. 112): das Bis-Datum muss in der Vergangenheit liegen und\ndarf nicht vor dem Ab-Datum liegen; das Ab-Datum darf höchstens vier Kalenderjahre\nzurückreichen, frühestens jedoch der 01.07.2023.\n\nEntsteht ein Entwurf, wird er wie jede Meldung erst nach Freigabe übermittelt.\n",
    "operationId": "dabpvHistorienanfrage",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwurf angelegt — `anfrage` zeigt den erzeugten Satz."
     },
     "422": {
      "description": "Nicht erstellt — `huerden` nennt den Grund (fehlendes Datum, Zeitraum unzulässig)."
     }
    }
   }
  },
  "/mandanten/{mandantId}/uv-stammdaten/rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "DSSD der DGUV übernehmen (UV-Stammdatendienst)",
    "description": "Body: `satz` (der rohe DSSD, mindestens 570 Zeichen), optional `pin`.\n\nDie DGUV schickt den DSSD auf zwei Wegen: als Antwort auf einen DSAS und **proaktiv**, wenn\nsich Gefahrtarifstellen ändern oder die Meldepflicht endet. Beide Wege laufen hier durch —\nein proaktiver Satz ohne vorherigen Abruf wird ebenfalls übernommen.\n\n⚠️ **Die Antwort ist keine Anzeige, sondern eine Anweisung.** Das Pflichtenheft verlangt an\neinem guten Dutzend Stellen die **maschinelle Übernahme**: laufende Nummer, Gültigkeit der\nUnternehmensnummer, Beitragsmaßstab, Gefahrtarifstellen. Sie werden unverändert gespeichert\n— auch Fremd-Gefahrtarifstellen, ohne Abgleich gegen die eigene UV-Datei.\n\n⚠️ Der **Beitragsmaßstab** ist die folgenreichste Angabe: er entscheidet, ob überhaupt ein\nLohnnachweis erwartet wird (4–6: keiner, und in den Folgejahren auch keine Abfrage mehr) und\nworauf er sich stützt (2 = Arbeitsstunden, 3 = Anzahl der Versicherten).\n\nMeldet der Satz das Ende der Zuständigkeit und wurde bereits ein Lohnnachweis übermittelt,\nist dieser zu **stornieren** — der Hinweis dazu landet im Posteingang. Gesendet wird nie\nautomatisch.\n",
    "operationId": "uvDssdRueckmeldung",
    "x-scope": "mandant:stammdaten",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Übernommen — `folgen` nennt, was daraus zu tun ist."
     },
     "422": {
      "description": "Kein verwertbarer DSSD"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/eau": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Elektronische AU-Bescheinigung bei der Krankenkasse anfordern (§ 109 SGB IV)",
    "description": "Body: `au_beginn` (jjjj-mm-tt, Pflicht), optional `annahmestelle_bbnr`.\n\n⚠️ **Die Sperrfristen sind der eigentliche Inhalt des Verfahrens** — die Kasse hat die\nDaten anfangs schlicht noch nicht. Angefordert wird frühestens ab dem **2. Kalendertag**\nder Arbeitsunfähigkeit; nach einer Zwischennachricht gelten **14 bzw. 28 Tage** Wartezeit.\nWird eine Sperre verletzt, antwortet der Weg mit `422` und nennt in `huerden`, woran es\nliegt, sowie in `frei_ab` den frühesten Tag.\n\n⚠️ Nur für **gesetzlich** Versicherte, und nur solange am Tag der Abwesenheit ein\nBeschäftigungsverhältnis bestand.\n\n🔴 Jede Anforderung erhält eine **eigene Datensatz-ID** und prüft sie gegen alle bereits\nübermittelten. Die Kasse ordnet ihre Rückmeldungen über dieses Feld zu; zwei Vorgänge mit\nderselben ID sind für sie ununterscheidbar.\n",
    "operationId": "eauAnfordern",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Anforderung als Entwurf angelegt (`id`, `dsid`)."
     },
     "422": {
      "description": "Eine Sperre greift — siehe `huerden` und `frei_ab`."
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen/{meldungId}/eau-rueckmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "meldungId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Antwort der Krankenkasse auf eine eAU-Anfrage übernehmen",
    "description": "Body: `gefunden`, `au_von`, `au_bis`, `festgestellt_am`, `art`, `krankenhaus` — oder\n`kennzeichen` für eine Zwischennachricht, oder `storniert: true`.\n\n⚠️ **Die Kennzeichen 4, 7 und 9 sind keine Antwort, sondern Zwischennachrichten**\n(Nachweis liegt nicht vor / in Prüfung / Weiterleitungsverfahren). Sie erzeugen keine\nFehlzeit, sondern einen Posteingang mit dem Tag, ab dem erneut angefragt werden darf.\n\n⚠️ Eine bestätigte AU wird zur **Fehlzeit** — aber sie überschreibt **nie stillschweigend**\neine vorhandene Fehlzeit und rührt keinen festgeschriebenen Monat an. In beiden Fällen\nentsteht stattdessen ein Posteingang mit dem Widerspruch; entschieden wird er von einem\nMenschen.\n\nZieht die Kasse ihre Rückmeldung zurück (`storniert: true`), wird die daraus entstandene\nFehlzeit **gelöscht** — AU-Daten sind Gesundheitsdaten. Nur wenn der Zeitraum bereits\nabgerechnet ist, wird sie stattdessen als ungültig gekennzeichnet.\n",
    "operationId": "eauRueckmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Verarbeitet — `art` sagt was geschah (uebernommen | zwischennachricht | konflikt | nicht_gefunden | storniert)."
     },
     "422": {
      "description": "Die Rückmeldung trifft keine Aussage"
     }
    }
   }
  },
  "/mandanten/{mandantId}/meldungen/{meldungId}/eau-storno": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "meldungId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Eine eAU-Anfrage zurücknehmen",
    "description": "⚠️ Zulässig **nur, solange keine fachliche Rückmeldung vorliegt**. Die Zwischennachrichten\n4, 7 und 9 stehen einer Stornierung nicht entgegen — wer sie als Antwort behandelt, sperrt\nden Storno zu früh.\n\nEin Entwurf, der nie hinausging, wird schlicht verworfen. Was gesendet wurde, bekommt einen\nStorno-Auftrag im Posteingang mit der Datensatz-ID der Ursprungsmeldung (`DSID_UR`); ohne\nsie weiß die Kasse nicht, welche Anfrage zurückgenommen wird.\n\n`frei_ab` nennt den Tag, ab dem erneut angefragt werden darf — die Frist läuft ab dem\n**Erhalt der Zwischennachricht**, nicht ab dem Storno.\n",
    "operationId": "eauStorno",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Zurückgenommen"
     },
     "409": {
      "description": "Nicht mehr möglich — eine fachliche Rückmeldung liegt vor."
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/unterbrechung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Beschäftigung unterbrechen (Austritt mit späterem Wiedereintritt)",
    "description": "Erfasst eine **Unterbrechung** des Beschäftigungsverhältnisses beim selben Arbeitgeber:\ndie Person tritt zum `austritt` aus und zum `wiedereintritt` wieder ein.\n\n⚠️ **Das ist nicht der Austritt der Person.** `PATCH /mitarbeiter` mit `austritt` beendet\ndas Arbeitsverhältnis endgültig. Hier bleibt es bestehen und bekommt eine Lücke:\nEintritt und Austritt der Person spannen weiter den äußeren Rahmen, die Monate innerhalb\nder Unterbrechung haben keine Beitragstage und kein anteiliges Entgelt.\n\nZwei Meldungen entstehen als **Entwurf**, in dieser Reihenfolge:\n\n1. die **Abmeldung** zum `austritt` (Abgabegrund 30 — oder 40/49, je nach Sachverhalt),\n2. die **Wiederanmeldung** zum `wiedereintritt` (Abgabegrund 10; Pflichtenheft\n   EA V2026.2 S. 138).\n\nOhne `wiedereintritt` läuft die Unterbrechung offen — die Person gilt ab dem Folgetag des\nAustritts als nicht beschäftigt, und es entsteht nur die Abmeldung.\n\n⚠️ Für die Angabe „Beschäftigt seit\" (Arbeitsbescheinigung, AAG-Erstattungsantrag) zählt\ndanach das **Wiedereintrittsdatum**, nicht der erste Eintritt (S. 321).\n",
    "operationId": "beschaeftigungUnterbrechen",
    "x-scope": "mandant:stammdaten",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "austritt"
        ],
        "properties": {
         "austritt": {
          "type": "string",
          "format": "date",
          "description": "letzter Tag der vorangehenden Beschäftigung"
         },
         "wiedereintritt": {
          "type": "string",
          "format": "date",
          "nullable": true,
          "description": "erster Tag der nächsten Beschäftigung; fehlt sie, läuft die Unterbrechung offen"
         },
         "grund": {
          "type": "string",
          "description": "Austrittsgrund der vorangehenden Beschäftigung"
         },
         "bemerkung": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Unterbrechung erfasst, Melde-Entwürfe angelegt",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "unterbrechung": {
           "type": "object"
          },
          "abmeldung": {
           "type": "object",
           "nullable": true
          },
          "anmeldung": {
           "type": "object",
           "nullable": true
          }
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NichtGefunden"
     },
     "422": {
      "description": "Die Angaben ergeben keine Unterbrechung — etwa weil der Wiedereintritt nicht nach dem\nAustritt liegt, der Austritt vor dem Eintritt der Person liegt, das Arbeitsverhältnis\nbereits endgültig beendet ist, oder weil am genannten Tag nach den bereits erfassten\nUnterbrechungen gar keine Beschäftigung besteht.\n"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/unterbrechungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Erfasste Unterbrechungen der Beschäftigung",
    "operationId": "beschaeftigungsUnterbrechungen",
    "x-scope": "mandant:stammdaten",
    "responses": {
     "200": {
      "description": "Liste, aufsteigend nach Austritt",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "unterbrechungen": {
           "type": "array",
           "items": {
            "type": "object"
           }
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/personalnummer-wechsel": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Personalnummer wechseln und mit der alten verknüpfen",
    "description": "Vergibt eine neue Personalnummer und **verknüpft** sie mit der bisherigen.\n\n🔴 **Ein Wechsel ist kein Umbenennen.** Drei Dinge passieren zusammen, und wer eines\nauslässt, erzeugt einen Schaden, der erst Monate später auffällt:\n\n1. Die **Verknüpfung** wird festgehalten — in beide Richtungen auflösbar\n   (`/personalnummern/{nummer}/kette`).\n2. Die alte Nummer wird **gesperrt**, nicht freigegeben. Sie wird erst nach einem\n   **vollen Kalenderjahr** wieder vergeben — Meldungen und Rückmeldungen laufen noch\n   lange nach dem Wechsel, und eine zu früh neu vergebene Nummer ordnet sie der\n   **falschen Person** zu.\n3. Die **Vortragswerte** gehen mit. Ohne sie verliert die Beitragsberechnung die\n   bisherigen Einmalzahlungen des Jahres, und die nächste wird nicht mehr korrekt gegen\n   die Jahres-Beitragsbemessungsgrenze geprüft — zu wenig Beitrag, unbemerkt.\n\n⚠️ Abgewiesen wird der Wechsel, wenn die neue Nummer bereits jemandem gehört oder noch\ngesperrt ist. Die Antwort nennt den Grund, statt still nichts zu tun.\n",
    "operationId": "personalnummerWechsel",
    "x-scope": "mandant:stammdaten",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "neu"
        ],
        "properties": {
         "neu": {
          "type": "string",
          "description": "übernehmende Personalnummer"
         },
         "gewechselt_am": {
          "type": "string",
          "format": "date"
         },
         "grund": {
          "type": "string",
          "description": "steht in den Lohnunterlagen"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "gewechselt"
     },
     "404": {
      "description": "Mitarbeiter unbekannt"
     },
     "422": {
      "description": "Nummer belegt oder gesperrt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/personalnummern/{nummer}/kette": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "nummer",
     "in": "path",
     "required": true,
     "schema": {
      "type": "string"
     }
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Kette einer Personalnummer — vorwärts und rückwärts",
    "description": "Liefert zu einer Personalnummer die **Vorgänger** und **Nachfolger**.\n\n⚠️ Das Pflichtenheft verlangt ausdrücklich **beide** Richtungen: „bei den Auswertungen zur\nalten Personalnummer wird die neue (übernehmende) angezeigt **und** bei der neuen\nPersonalnummer ist die alte Referenzpersonalnummer erkennbar\". Wer nur eine Richtung\nbaut, hat die Hälfte — und zwar die, die er selbst gerade brauchte.\n",
    "operationId": "personalnummerKette",
    "x-scope": "mandant:stammdaten",
    "responses": {
     "200": {
      "description": "Kette"
     }
    }
   }
  },
  "/mandanten/{mandantId}/personalnummern/mehrfachvergaben": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Dieselbe Versicherungsnummer unter mehreren Personalnummern",
    "description": "Der vom Pflichtenheft **empfohlene** Abgleich: erkennt Personen, die unter mehreren\nPersonalnummern geführt werden.\n\n⚠️ Es ist ein **Hinweis**, keine Abweisung. Dieselbe Person kann legitim zwei Nummern\nhaben — zwei Beschäftigungen im selben Betrieb, oder ein noch nicht vollzogener Wechsel.\nWer daraus einen Fehler macht, blockiert gültige Fälle.\n\nBereits verknüpfte Nummernpaare erscheinen nicht mehr: der Anwender hat gehandelt.\n",
    "operationId": "personalnummerMehrfachvergaben",
    "x-scope": "mandant:stammdaten",
    "responses": {
     "200": {
      "description": "Treffer"
     }
    }
   }
  },
  "/mandanten/{mandantId}/deuev/bestandsanmeldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Bestandsanmeldung zum DEÜV-Systembeginn (GD 13) erzeugen",
    "description": "Systemwechsel (Pflichtenheft 0104 S. 127): alle Beschäftigten mit Eintritt **vor** dem DEÜV-Systembeginn des Mandanten\n(`deuev_systembeginn`), die noch keinen gemeldeten Stand haben, werden **zum Systembeginn mit Grund 13** angemeldet —\nals Entwürfe. Das Altsystem meldet dieselben Personen mit Grund 36 ab. Idempotent; ohne gesetzten Systembeginn 422.\nEintritte am oder nach dem Systembeginn bekommen die gewöhnliche Anmeldung 10 beim Anlegen der Person.\n",
    "operationId": "deuevBestandsanmeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Nichts Neues — alle übersprungen (`uebersprungen`) oder Hürden (`huerden`)."
     },
     "201": {
      "description": "Entwürfe angelegt (`erzeugt`: Person, Meldung, Grund, Beginn)."
     },
     "422": {
      "description": "Kein DEÜV-Systembeginn gesetzt."
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/minijob-befreiung": {
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Befreiungsantrag RV anzeigen (Minijob-Altfall, Gründe 33/13)",
    "description": "Anzeige des **Antrags auf Befreiung von der Rentenversicherungspflicht** (§ 6 Abs. 1b\nSGB VI) gegenüber der Minijob-Zentrale. Body: `erhoehung_ab` (JJJJ-MM-TT, Tag ab dem das\nerhöhte Entgelt gilt).\n\nPflichtenheft S. 186 · Kriterium 976a3f20. Der Altfall: geringfügig Beschäftigte (PGS\n109), deren Beschäftigung **vor dem 01.01.2013** begann, mit einer Entgelterhöhung danach\n**über 400 €** und einem Antrag im **ersten Monat** der Erhöhung.\n\n⚠️ **Gründe 33/13, nicht 32/12.** Die Beitragsgruppe wechselt, der Sachverhalt ist\ntrotzdem ein „sonstiger Grund\" — beide wären formal zulässig, keine Kernprüfung sieht den\nUnterschied.\n\n⚠️ **Entsteht nie automatisch** — der Antrag ist ein Papier des Beschäftigten. Der Tag\nseines Eingangs steht als `rv_befreiung_antrag_am` an der Zeitscheibe.\n\n⚠️ Die Befreiung wirkt ab dem Monat des Eingangs nur, wenn die Meldung die Minijob-Zentrale\n**binnen sechs Wochen** erreicht (§ 6 Abs. 1b S. 3 SGB VI) — sonst erst ab dem Folgemonat\nder Meldung. Der Hinweis steht in der Antwort.\n",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Meldepaar 33/13 als Entwürfe angelegt."
     },
     "404": {
      "description": "Mitarbeiter unbekannt"
     },
     "422": {
      "description": "Die Voraussetzungen des Altfalls sind nicht erfüllt — `fehler.meldung` nennt ALLE fehlenden."
     }
    }
   }
  },
  "/mandanten/{mandantId}/deuev/systemwechsel": {
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Abmeldungen bei Wechsel des Entgeltabrechnungssystems (Grund 36)",
    "description": "Das **Gegenstück zur Bestandsanmeldung**: verlässt der Mandant dieses System, wird für jeden\nBeschäftigten der bis dahin gemeldete Zeitraum mit **Abgabegrund 36** abgeschlossen. Das neue\nSystem meldet die Menschen mit Grund 13 wieder an.\n\nPflichtenheft S. 127 · Kriterium 3b975d05 (F1). ⚠️ Ohne diese Meldung bleibt der Bestand bei\nden Einzugsstellen offen — zwei Systeme melden dieselbe Beschäftigung.\n\n⚠️ **Keine Abmeldung der Beschäftigung**: kein Austrittsdatum, keine Wirkung auf Lohnkonto\noder Beitragsnachweis. Der DEÜV-Stand wird geschlossen, damit hier nichts mehr entsteht.\n\n⚠️ **Entsteht nie automatisch** — das Datum kennt nur der Anwender. Erzeugt werden Entwürfe;\ngesendet wird nur nach Freigabe.\n",
    "x-scope": "mandant:meldungen",
    "parameters": [
     {
      "$ref": "#/components/parameters/MandantId"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "systemende"
        ],
        "properties": {
         "systemende": {
          "type": "string",
          "format": "date",
          "description": "Letzter Tag, für den dieses System meldet."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Nichts zu melden (kein gemeldeter Stand offen)."
     },
     "201": {
      "description": "Entwürfe angelegt."
     },
     "422": {
      "description": "`systemende` fehlt, ist kein Datum oder liegt vor dem DEÜV-Systembeginn.\n"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/eel/ende-anfordern": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "EEL — Ende der Entgeltersatzleistung anfordern (Grund 42, DBEE)",
    "description": "**Ausschließlich auf Anwendervorgabe** (Pflichtenheft S. 217): die Kasse meldet das Ende der Leistung in der Regel\nproaktiv (Grund 62); die Anforderung ist für Fälle ohne zeitnahe Rückmeldung gedacht. Body: `eel_ab` (Beginn der\nEntgeltersatzleistung, JJJJ-MM-TT), optional `fehlzeit_id`. Entwurf, Freigabe erforderlich. Die Antwort der Kasse\n(62) wird im Posteingang abgelegt und der Anforderung zugeordnet (`beantwortet_durch`); ENDEGRUND 01 erzeugt den\nHinweis „Fehlzeit korrigieren/stornieren\".\n",
    "operationId": "eelEndeAnfordern",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "eel_ab"
        ],
        "properties": {
         "eel_ab": {
          "type": "string",
          "format": "date"
         },
         "fehlzeit_id": {
          "type": "integer"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Entwurf angelegt (`meldung_id`, Grund 42)"
     },
     "422": {
      "description": "Hürde (z. B. keine Annahmestelle, kein Ansprechpartner) oder `eel_ab` fehlt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/fehlzeiten/{id}/vorerkrankungsanfrage": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "EEL — Vorerkrankungsanfrage (Grund 41, DBVO) zu einer Krankheits-Fehlzeit anstoßen",
    "description": "Dieselbe Regel wie der automatische Auslöser (Fehlzeit-POST, Betriebsautomatik): nur gesetzlich Versicherte (nicht\nPGR 109/110/190), aktuelle AU attestiert UND mindestens eine frühere attestierte AU, zwischen Beginn der aktuellen\nund Ende der letzten AU höchstens 6 Monate, die 6-Monats-Kette zusammen mit der aktuellen AU ≥ 30 Tage (offenes\nEnde = heute + 7). Nur attestierte Zeiten gehen in den DBVO (Pflichtenheft S. 226/227, VB EEL 3.12). Entwurf.\n",
    "operationId": "eelVorerkrankungsanfrage",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Anfrage existiert schon (`vorhanden`)"
     },
     "201": {
      "description": "Entwurf angelegt (`meldung_id`, `pruefung`)"
     },
     "422": {
      "description": "Nicht zulässig (Grund im `detail`) oder Hürde"
     }
    }
   }
  },
  "/mandanten/{mandantId}/eel/faelle": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "EEL-Fälle mit Zustand (laufend/beendet, offene Anforderungen, Rückmeldungen)",
    "description": "Ein Fall = auslösende Fehlzeit + unsere Meldungen (Bescheinigung, 41/42, 51, 99) + die Rückmeldungen der Kasse\n(61/62/71). `laufend` steuert den Wechsel der meldenden Stelle: Grund 99 entsteht nur in laufenden Fällen\n(Pflichtenheft S. 206), unbeantwortete 41/42 werden erneut abgesetzt (S. 205) — beides als Entwürfe, ausgelöst\ndurch `PATCH /mandanten/{id}` mit geänderter Betriebsnummer (`eel_wechsel_meldende_stelle` in der Antwort).\n",
    "operationId": "eelFaelle",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`faelle[]`"
     }
    }
   }
  },
  "/stammdaten/rechtsformen": {
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Rechtsform-Codeliste der Bundesagentur für den DSBD",
    "description": "Die amtliche „Codeliste DSBD\" (71 Einträge, **dreistelliger** Schlüssel) aus den Anlagen zur\nVerfahrensanforderung DSBD V2.32. `plausibilisierbar` ist Spalte „A\" — kann das Programm\nName ↔ Rechtsform maschinell prüfen?\n⚠️ Nicht zu verwechseln mit `/kataloge/dxbd-rechtsformen`: das Dialogverfahren der\nBundesagentur führt eine eigene, **fünfstellige** Codeliste.\nOhne Mandantenbezug: ein öffentlicher Katalog, keine Personendaten.\n",
    "operationId": "dsbdRechtsformen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`rechtsformen[]` mit `schluessel`, `auswahl_lang`, `plausibilisierbar`"
     }
    }
   }
  },
  "/kataloge/dxbd-rechtsformen": {
   "get": {
    "tags": [
     "Stammdaten"
    ],
    "summary": "Rechtsform-Codeliste der Bundesagentur (Dialogverfahren Betriebsdatenpflege)",
    "description": "Die amtliche Codeliste der BA für den Rechtsformschlüssel des DXBD (73 Einträge, fünfstellig).\nSie stammt aus der Verfahrensanforderung DXBD/DXBE V1.3 und liegt versioniert im Repo;\n`plausibilisierbar` ist Spalte „A\" — kann das Programm Name ↔ Rechtsform maschinell prüfen?\n⚠️ Nicht zu verwechseln mit dem dreistelligen Rechtsformschlüssel des DSBD-Verfahrens.\nOhne Mandantenbezug: ein öffentlicher Katalog, keine Personendaten.\n",
    "operationId": "dxbdRechtsformen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`rechtsformen[]` mit `schluessel`, `auswahl_lang`, `plausibilisierbar`"
     }
    }
   }
  },
  "/mandanten/{mandantId}/aag/rueckmeldungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "AAG — Rückmeldungen der Umlagekassen (DSRA/DBRA) auf Erstattungsanträge",
    "description": "Was die Umlagekasse zu einem U1-/U2-Erstattungsantrag zurückgemeldet hat: `beantragt_cent` und\n`festgestellt_cent` nebeneinander, dazu `abweichung_cent`, `kennzeichen_feststellung`\n(1 vollständig · 2 teilweise · 3 nicht entsprochen) und `grund_abweichung` (00–32).\nZugeordnet wird über die Datensatz-ID unseres DSER. Eingang: `POST /eingang`.\n⚠️ Es wird nichts umgebucht — eine Kürzung ist eine Entscheidung der Kasse.\n",
    "operationId": "aagRueckmeldungen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`rueckmeldungen[]`"
     }
    }
   }
  },
  "/mandanten/{mandantId}/eel/rueckmeldungen": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "EEL — Rückmeldungen der Kasse (61/62/71 …), strukturiert gelesen",
    "description": "Was der Posteingangs-Verteiler aus dem DSLW der Kasse gelesen hat (DBHE Höhe der Leistung, DBEE Ende/Verlängerung,\nDBVO anrechenbare Vorerkrankungen, DBID) und was daraus folgte (`verarbeitet`: Hinweise, DBBE-Entwurf nach § 23c).\nEingang: `POST /eingang` bzw. der Abruf vom Kommunikationsserver.\n",
    "operationId": "eelRueckmeldungen",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "`rueckmeldungen[]`"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/gesonderte-meldung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Gesonderte Meldung (GD 57, § 194 SGB VI) auf Anforderung erzeugen",
    "description": "Body: `zeitraum_von`, `zeitraum_bis` (JJJJ-MM-TT, ein Kalenderjahr), `anlass` (`rentenantrag` | `auskunftsersuchen`).\n\n⚠️ **Nachrangig:** eine Entgeltmeldung aus einem anderen Tatbestand (GD 30–49, 51–53, 70–72) geht vor — nur\ndie Jahresmeldung tritt zurück. ⚠️ Fällig **mit der Abrechnung des letzten Monats** des Zeitraums: ist er noch\nnicht abgerechnet, wird die Anforderung im Posteingang **vorgemerkt** und beim Festschreiben erzeugt\n(`vorgemerkt` in der Antwort). Die Folgemeldung beginnt am Anschlusstag; eine später entstehende vorrangige\nMeldung storniert die Gesonderte Meldung und meldet den Rest erneut.\n",
    "operationId": "gesonderteMeldung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "zeitraum_von",
         "zeitraum_bis",
         "anlass"
        ],
        "properties": {
         "zeitraum_von": {
          "type": "string",
          "format": "date"
         },
         "zeitraum_bis": {
          "type": "string",
          "format": "date"
         },
         "anlass": {
          "type": "string",
          "enum": [
           "rentenantrag",
           "auskunftsersuchen"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Vorgemerkt (`vorgemerkt` = Posteingangs-ID) oder Hürden (`huerden`)."
     },
     "201": {
      "description": "Entwurf angelegt (`meldung_id`)."
     },
     "404": {
      "description": "Mitarbeiter unbekannt."
     },
     "422": {
      "description": "Zeitraum oder Anlass unzulässig."
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/arbeitsbescheinigung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Arbeitsbescheinigung erzeugen (§§ 312 f. SGB III, BEA)",
    "description": "Erzeugt die elektronische Arbeitsbescheinigung als **Entwurf**.\n\n🔴 **Auf Verlangen, nicht beim Austritt.** `verlangt_von` (`bundesagentur` |\n`beschaeftigter`) ist Pflicht — es gibt bewusst **keinen** automatischen Auslöser. Wer\ndie Bescheinigung an den Austritt hängt, meldet der Bundesagentur Daten zu Menschen, die\nnie Arbeitslosengeld beantragen.\n\n⚠️ **Der Rückblick ist nicht pauschal zwölf Monate.** Liegen in zwölf Monaten weniger als\n**150 Kalendertage mit Entgeltzahlung**, sind **24** Monate zu bescheinigen — die Antwort\nnennt den ermittelten Umfang samt Begründung unter `umfang`.\n\n⚠️ **Testamentsprinzip:** es wird nicht storniert. Eine spätere Bescheinigung ersetzt die\nfrühere; es gilt die mit dem jüngsten Erstellungsdatum.\n",
    "operationId": "arbeitsbescheinigung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwurf erzeugt — oder Hürden benannt (`meldung_id: null`)."
     },
     "422": {
      "description": "`verlangt_von` fehlt oder ist unzulässig"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/nebeneinkommensbescheinigung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Nebeneinkommensbescheinigung erzeugen (§ 313 SGB III, BEA · DSNE)",
    "description": "Erzeugt die Nebeneinkommensbescheinigung für **einen Kalendermonat** (`monat`, YYYY-MM) als\n**Entwurf** — wer Arbeitslosengeld bezieht und nebenher arbeitet.\n\n🔴 **`konstant` ist eine Pflichtangabe ohne Vorbelegung** (true/false): bleiben Entgelt und\nwöchentliche Arbeitszeit künftig gleich? Die Bundesagentur rechnet mit dem gemeldeten Wert\n**weiter, bis eine neue Meldung eingeht** — eine geratene Antwort erzeugt Rückforderungen.\nFehlt sie, entsteht kein Datensatz, sondern eine Hürde.\n\n⚠️ `verlangt_von` (`bundesagentur` | `beschaeftigter`) ist Pflicht — auf Verlangen, nie\nautomatisch. ⚠️ Bei Personengruppe 109 wird **kein** SV-Brutto übermittelt (Grundstellung).\n⚠️ Eine Einmalzahlung braucht `einmalzahlung_netto_cent` und den Zeitraum\n`einmalzahlung_von`/`einmalzahlung_bis` — das Prüfprogramm verlangt ihn zu jeder Einmalzahlung.\n",
    "operationId": "nebeneinkommensbescheinigung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwurf (DSNE) erzeugt — oder Hürden benannt (`meldung_id: null`)."
     },
     "422": {
      "description": "`verlangt_von` oder `monat` fehlt oder ist unzulässig"
     }
    }
   }
  },
  "/mandanten/{mandantId}/mitarbeiter/{id}/arbeitsbescheinigung-eu": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "EU-Arbeitsbescheinigung erzeugen (§ 312a SGB III, BEA · DSEU)",
    "description": "Erzeugt die Arbeitsbescheinigung für Zwecke des zwischen- und überstaatlichen Rechts\n(Grundlage des PD U1) als **Entwurf**.\n\n⚠️ **Der Bescheinigungszeitraum steht im Anschreiben der Bundesagentur** — jedes Land\nbraucht andere Zeiträume. `bescheinigung_von` (YYYY-MM) übernimmt ihn; ohne Angabe gelten\ndie 24 Monate des Pflichtenhefts. **Lücken im Rückblick sind eine Hürde**, kein stilles\nKürzen (`luecken_akzeptiert: true` macht sie zum Hinweis).\n\n⚠️ Arbeitszeitänderungen brauchen den Grund (`arbeitszeitaenderungen: [{ab, grund 01–12,\nwochenstunden}]`); bei 01/02/05/06 sind 60 statt 24 Monate zu bescheinigen. Fehlzeiten, die\nsich nicht eindeutig auf die BA-Schlüssel der Anlage 5 abbilden lassen, nennt die Antwort als\nHürde — `fehlzeiten_ba: {fehlzeitId: art}` legt sie fest. Eine Kündigung braucht\n`beendigung.kuendigung_am` und `kuendigungsfrist_wochen`; nur ein befristetes\nArbeitsverhältnis mit Fristablauf kommt ohne Datum aus.\n",
    "operationId": "arbeitsbescheinigungEu",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwurf (DSEU) erzeugt — oder Hürden benannt (`meldung_id: null`)."
     },
     "422": {
      "description": "`verlangt_von` fehlt oder ist unzulässig"
     }
    }
   }
  },
  "/mandanten/{mandantId}/eubp": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "euBP-Gesamtlieferung vorbereiten (§ 28p Abs. 6a SGB IV)",
    "description": "Erzeugt die **Gesamtlieferung** für einen Prüftermin der elektronisch unterstützten\nBetriebsprüfung — die amtlichen Datensätze nach Anlage 1 der Grundsätze euBP (V3.5.0:\nVOSZ · DSKO · DSST · DSZE · DSFB · DSAG · DSBN · DSAN/DSLA · NCSZ, mit den Bausteinen\nDBFZ/DBKG/DBSC/DBRB) — als **Entwurf**. Übermittelt wird nichts. Geprüft wird mit der\nSatzprüfung aus dem euBP-Datentool der DRV (`npm run kernpruefung:eubp`).\n\nBody: entweder `pruefzeitraum_von`/`pruefzeitraum_bis` (YYYY-MM) aus der Prüfanmeldung —\noder nur `prueftermin` (YYYY-MM-DD); dann wird der Übermittlungszeitraum mit **fünf\nKalenderjahren vor dem Prüftermin vorbelegt**. Optional `liefertermin` (spätester\nLiefertermin), `uebermittlung_von`/`uebermittlung_bis` (der Anwender ändert den\nZeitraum), `vorgang_id` (Neulieferung zu einem bestehenden Prüfvorgang) und\n`anwenderangaben`: `pruefbescheid_elektronisch` (Pflicht, ohne Vorbelegung), `gddue`\n(1 Prüftermin · 2 Programmwechsel · 3 Dienstleisterwechsel — Pflicht, ohne Vorbelegung),\n`anrede_ap` (M|W für den Kommunikationssatz), `zugangseroeffnung.email_ep` (DSZE, Pflicht bei\nelektronischem Prüfbescheid), `fragebogen` (DSFB, optional: `kennzlstap`, `kennzwg`,\n`kennzfm`), `personen_angaben` (je Mitarbeiter-ID z. B. `{ rentenbezieher: true }`).\nDie Angaben werden im **Prüfvorgang** gespeichert (`vorgang_id` in der Antwort).\n\n⚠️ **Der Übermittlungszeitraum ist größer als der Prüfzeitraum.** Dazu gehören das\nAbrechnungsjahr **vor** dem Prüfzeitraum und das laufende Jahr bis zum letzten\n**abgerechneten** Monat. Die Antwort nennt ihn unter `uebermittlungszeitraum`.\n\n⚠️ Ein **Neuversand setzt eine Stornierung voraus** — eine eigene Sendung über\n`POST /eubp/{meldungId}/storno`; sonst lägen zwei Lieferungen zum selben Prüftermin vor.\nNach der Statusmeldung **E90** ist die Prüfung abgeschlossen und keine Lieferung mehr\nmöglich.\n\n⚠️ Kein Mussfeld bekommt einen Ersatzwert: fehlt z. B. der Rentenbezug einer Person (DSAN\nKENNZRBZ), entsteht keine Lieferung, sondern eine Hürde, die die Person und den Weg nennt.\n",
    "operationId": "eubpLieferung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Entwurf erzeugt — oder Hürden benannt (dann `meldung_id: null`); immer mit `vorgang_id`."
     },
     "422": {
      "description": "Prüfzeitraum/Prüftermin unplausibel"
     }
    }
   }
  },
  "/mandanten/{mandantId}/eubp/vorbelegung": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "Vorbelegung des euBP-Übermittlungszeitraums ansehen",
    "description": "Query: `prueftermin` (YYYY-MM-DD) **oder** `pruefzeitraum_von`/`pruefzeitraum_bis`\n(YYYY-MM). Liefert den Zeitraum, der bei `POST /eubp` gelten würde — fünf Kalenderjahre vor\ndem Prüftermin bzw. Prüfzeitraum + Jahr davor + laufendes Jahr bis zum letzten\nabgerechneten Monat —, dazu den ersten abgerechneten Monat (davor liegt nichts in\nLohnfluss) und die Hinweise. Der Anwender darf den Zeitraum ändern (`aenderbar: true`).\n",
    "operationId": "eubpVorbelegung",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Zeitraum mit Begründung — oder `zeitraum: null`, wenn nichts abgerechnet ist."
     },
     "422": {
      "description": "weder Prüftermin noch Prüfzeitraum"
     }
    }
   }
  },
  "/mandanten/{mandantId}/eubp/{meldungId}/storno": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "meldungId",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "post": {
    "tags": [
     "SV-Meldeverfahren"
    ],
    "summary": "euBP-Gesamtlieferung stornieren (eigene Sendung)",
    "description": "Erzeugt die **Stornosendung** zu einer Gesamtlieferung — genau VOSZ · DSKO · DSST mit\nKENNZST = J · NCSZ, mit BBNRAS/BBNRMS/ZRVON/ZRBIS/GDDUE der stornierten Sendung\n(Grundsätze euBP 6.6, Anlage 5). Sie trägt keine Daten; erst danach ist zu diesem\nPrüftermin eine Neulieferung möglich (`POST /eubp` mit derselben `vorgang_id`).\n\n⚠️ Nach der Statusmeldung **E90** ist keine Stornierung mehr möglich; eine bereits\nstornierte Lieferung wird nicht ein zweites Mal storniert (422).\n",
    "operationId": "eubpStorno",
    "x-scope": "mandant:meldungen",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Stornosendung als Entwurf angelegt (`meldung_id`, `storno_von`)."
     },
     "404": {
      "description": "Lieferung nicht bei diesem Mandanten"
     },
     "422": {
      "description": "bereits storniert, Prüfung abgeschlossen (E90) oder kein Lieferungssatz"
     }
    }
   }
  },
  "/mandanten/{mandantId}/benutzer": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    }
   ],
   "get": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Benutzer des Mandanten",
    "operationId": "benutzerListe",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Liste"
     }
    }
   },
   "post": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Benutzer anlegen",
    "description": "**Kein Passwort über die API.** Es wird weder entgegengenommen noch zurückgegeben — der\nBenutzer setzt es selbst über den Zurücksetzen-Weg des Portals. Ein API-Feld dafür wäre\nein Passwort im Anfrage-Protokoll.\n",
    "operationId": "benutzerAnlegen",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "201": {
      "description": "Angelegt"
     }
    }
   }
  },
  "/mandanten/{mandantId}/benutzer/{id}": {
   "parameters": [
    {
     "$ref": "#/components/parameters/mandantId"
    },
    {
     "name": "id",
     "in": "path",
     "required": true,
     "schema": {
      "type": "integer"
     }
    }
   ],
   "patch": {
    "tags": [
     "Verwaltung"
    ],
    "summary": "Benutzer ändern (Name, Rolle, aktiv)",
    "description": "Der **letzte aktive Administrator** kann weder herabgestuft noch deaktiviert werden\n(409). Ohne diesen Riegel kann ein Mandant sich die Verwaltung seines eigenen Zugangs\nnehmen — und niemand außer uns kommt wieder hinein.\n",
    "operationId": "benutzerAendern",
    "x-scope": "mandant:verwaltung",
    "x-baustand": "verfuegbar",
    "responses": {
     "200": {
      "description": "Geändert"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "bearerAuth": {
    "type": "http",
    "scheme": "bearer",
    "description": "`Authorization: Bearer lk_live_…` (bzw. `lk_test_…` in der Sandbox — gleiche Adresse,\nder Schlüssel entscheidet). Ein `lk_test_`-Schlüssel erreicht ausschließlich\nSandbox-Mandanten und umgekehrt; aus der Sandbox wird **nichts** an die Sozialversicherung\nübermittelt, und Geld-Dateien (SEPA/DATEV) tragen die Markierung `SANDBOX`. Der Schlüssel\nliegt bei uns ausschließlich als SHA-256-Hash. Jeder Key trägt eine Liste von Scopes;\nfehlt der für einen Endpunkt nötige, kommt `403 AUTH` mit dem Namen im `detail`.\n"
   }
  },
  "parameters": {
   "mandantId": {
    "name": "mandantId",
    "in": "path",
    "required": true,
    "description": "Id des Arbeitgebers.",
    "schema": {
     "type": "integer"
    }
   },
   "monat": {
    "name": "monat",
    "in": "path",
    "required": true,
    "schema": {
     "type": "string",
     "pattern": "^\\d{4}-\\d{2}$"
    },
    "example": "2026-07"
   },
   "elstamAnlass": {
    "name": "anlass",
    "in": "path",
    "required": true,
    "schema": {
     "type": "string",
     "enum": [
      "anmeldung",
      "abmeldung",
      "ummeldung"
     ]
    }
   },
   "idempotencyKey": {
    "name": "Idempotency-Key",
    "in": "header",
    "required": false,
    "description": "Frei gewählter Schlüssel (max. 80 Zeichen). Ein zweiter Aufruf mit demselben Schlüssel,\nderselben Methode und demselben Pfad liefert innerhalb von **24 Stunden** die\ngespeicherte Antwort zurück, statt die Aktion erneut auszuführen.\n",
    "schema": {
     "type": "string",
     "maxLength": 80
    }
   }
  },
  "responses": {
   "Auth": {
    "description": "`AUTH` — Key fehlt, ist unbekannt oder deaktiviert.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Fehler"
      }
     }
    }
   },
   "Scope": {
    "description": "`AUTH` — Scope fehlt, oder der Key gehört zu einem anderen Mandanten.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Fehler"
      }
     }
    }
   },
   "NichtGefunden": {
    "description": "`NICHT_GEFUNDEN` — die Ressource gibt es nicht (oder nicht für diesen Mandanten).",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Fehler"
      }
     }
    }
   }
  },
  "schemas": {
   "UvTraeger": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "bbnr_uv": {
      "type": "string"
     },
     "unternehmensnummer": {
      "type": "string"
     },
     "gueltig_ab": {
      "type": "string",
      "format": "date"
     },
     "gueltig_bis": {
      "type": "string",
      "format": "date",
      "nullable": true
     },
     "notiz": {
      "type": "string",
      "nullable": true
     }
    }
   },
   "MaGefahrtarifstelle": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "bbnr_uv": {
      "type": "string"
     },
     "gefahrtarifstelle": {
      "type": "string"
     },
     "anteil_prozent": {
      "type": "number"
     },
     "gueltig_ab": {
      "type": "string",
      "format": "date"
     },
     "gueltig_bis": {
      "type": "string",
      "format": "date",
      "nullable": true
     }
    }
   },
   "Vortrag": {
    "type": "object",
    "description": "Ein Jahres-Anfangsbestand. Beträge in **Cent**, wie überall in dieser API.\n\n⚠️ **Erfasste Werte werden gegen die ANTEILIGE Beitragsbemessungsgrenze je Zweig geprüft**\n(Jahres-BBG × SV-Tage / 360). Ein Vortrag darüber kann in keinem Vorsystem entstanden sein\nund wird mit 422 abgewiesen — er würde sonst die SV-Luft für Einmalzahlungen verfälschen,\nohne dass irgendetwas auffällt.\n\n⚠️ **Eine Zeile mit 0 ist etwas anderes als keine Zeile.** Ein ausdrücklich mit 0 Entgelt und\n0 SV-Tagen erfasster Vortrag (z. B. ganzjährige Elternzeit) wird als echte Vorgabe behandelt,\nnicht als fehlender Wert.\n",
    "properties": {
     "art": {
      "type": "string",
      "enum": [
       "eigene_firma",
       "fremdfirma"
      ],
      "description": "`eigene_firma` = Systemwechsel beim selben Arbeitgeber (wird bescheinigt) ·\n`fremdfirma` = früherer Arbeitgeber (wird **nicht** bescheinigt).\n"
     },
     "brutto_cent": {
      "type": "integer",
      "minimum": 0,
      "description": "steuerpflichtiger Bruttoarbeitslohn"
     },
     "lohnsteuer_cent": {
      "type": "integer",
      "minimum": 0
     },
     "soli_cent": {
      "type": "integer",
      "minimum": 0
     },
     "kirchensteuer_cent": {
      "type": "integer",
      "minimum": 0
     },
     "svbrutto_laufend_cent": {
      "type": "integer",
      "minimum": 0,
      "description": "Nur bei `eigene_firma` — die SV-Luft (§ 23a) ist arbeitgeberbezogen."
     },
     "einmalzahlung_cent": {
      "type": "integer",
      "minimum": 0,
      "description": "Nur bei `eigene_firma`."
     },
     "sv_tage": {
      "type": "integer",
      "minimum": 0,
      "maximum": 366
     },
     "quelle": {
      "type": [
       "string",
       "null"
      ],
      "description": "Vorsystem bzw. früherer Arbeitgeber."
     },
     "uv_bbnr": {
      "type": [
       "string",
       "null"
      ],
      "description": "Betriebsnummer des UV-Trägers zum Vortrag."
     },
     "uv_gefahrtarifstelle": {
      "type": [
       "string",
       "null"
      ],
      "description": "Pflicht, sobald `uv_entgelt_cent` gesetzt ist — ohne sie ist der Betrag keiner Stelle zuzuordnen."
     },
     "uv_entgelt_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Uv-pflichtiges Arbeitsentgelt aus dem Vorsystem beim **unterjährigen Systemwechsel**.\n\n⚠️ Wirkt **ausschließlich in der UV-Jahresmeldung (Grund 92)**, nicht im elektronischen\nLohnnachweis: den Nachweis für die Zeit vor dem Wechsel erstattet das abgebende System.\nBeides zu melden ergäbe bei der Berufsgenossenschaft ein doppeltes Entgelt.\n"
     },
     "uv_stunden": {
      "type": [
       "number",
       "null"
      ],
      "minimum": 0,
      "description": "UV-Arbeitsstunden aus dem Vorsystem — ebenfalls nur für Grund 92."
     },
     "umlage_entgelt_u1_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Umlagepflichtiges Arbeitsentgelt U1 (AAG)."
     },
     "umlage_entgelt_u2_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Umlagepflichtiges Arbeitsentgelt U2 (AAG)."
     },
     "umlage_entgelt_inso_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Umlagepflichtiges Arbeitsentgelt Insolvenzgeldumlage."
     },
     "sv_tage_kv": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "maximum": 366,
      "description": "SV-Tage KV; `null` = es gilt `sv_tage`."
     },
     "sv_tage_rv": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "maximum": 366
     },
     "sv_tage_av": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "maximum": 366
     },
     "sv_tage_pv": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "maximum": 366
     },
     "sv_luft_kv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "**Alternative** zu Entgelt + SV-Tagen: die verbleibende SV-Luft je Zweig. „Es ist auch\nzulässig, die entsprechende SV-Luft je Versicherungszweig vorzugeben.\"\n"
     },
     "sv_luft_rv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0
     },
     "sv_luft_av_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0
     },
     "sv_luft_pv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0
     },
     "einzugsstelle_ik": {
      "type": [
       "string",
       "null"
      ],
      "description": "Einzugsstelle, unter der die Vortragswerte entstanden sind."
     },
     "versorgungswerk": {
      "type": [
       "string",
       "null"
      ],
      "description": "Zuordnung zur berufsständischen Versorgungseinrichtung."
     },
     "personengruppe": {
      "type": [
       "string",
       "null"
      ],
      "description": "Personengruppenschlüssel des Vorsystems (Beleg)."
     },
     "beitragsgruppe": {
      "type": [
       "string",
       "null"
      ],
      "description": "Beitragsgruppenschlüssel des Vorsystems (Beleg)."
     },
     "pv_kinder": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "maximum": 20,
      "description": "Berücksichtigungsfähige Kinder für den PV-Abschlag."
     },
     "fehlzeiten": {
      "type": [
       "array",
       "null"
      ],
      "items": {
       "type": "object"
      },
      "description": "Fehlzeiten des Vorsystems `[{typ, von, bis}]` — Beleg, keine Rechengröße."
     }
    }
   },
   "ApiSchluessel": {
    "type": "object",
    "description": "Ein API-Schlüssel — **ohne** seinen Geheimwert. Der ist nur im Moment der Erzeugung\nsichtbar; gespeichert wird ausschließlich sein SHA-256-Hash.\n",
    "properties": {
     "id": {
      "type": "integer"
     },
     "label": {
      "type": "string",
      "description": "Wofür er da ist; erscheint im Protokoll als Akteur."
     },
     "scopes": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Die Berechtigungen dieses Schlüssels."
     },
     "aktiv": {
      "type": "integer",
      "description": "1 = nutzbar, 0 = abgeschaltet."
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "zuletzt_benutzt_am": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time",
      "description": "Letzter erfolgreicher Aufruf. `null` = noch nie benutzt — ein Hinweis auf einen vergessenen Schlüssel."
     }
    }
   },
   "Fehler": {
    "type": "object",
    "description": "Einheitliches Fehlerbild — jede Fehlerantwort sieht so aus, unabhängig vom Endpunkt.\n",
    "required": [
     "fehler"
    ],
    "properties": {
     "fehler": {
      "type": "object",
      "required": [
       "code",
       "titel"
      ],
      "properties": {
       "code": {
        "type": "string",
        "description": "Maschinenlesbare Kategorie.",
        "enum": [
         "AUTH",
         "VALIDIERUNG",
         "NICHT_GEFUNDEN",
         "ZEITSCHEIBE_KONFLIKT",
         "LAUF_STATUS",
         "IDEMPOTENZ_KONFLIKT",
         "ANNAHMESTELLE",
         "LSTA",
         "LSTB",
         "ELSTAM",
         "DLS",
         "ERIC_FEHLT"
        ]
       },
       "titel": {
        "type": "string",
        "description": "Kurzer Klartext."
       },
       "detail": {
        "type": [
         "string",
         "null"
        ],
        "description": "Ergänzung — oft das betroffene Feld oder die erlaubten Werte."
       }
      }
     }
    },
    "example": {
     "fehler": {
      "code": "VALIDIERUNG",
      "titel": "Pflichtfeld fehlt",
      "detail": "kasse_ik"
     }
    }
   },
   "MandantEingabe": {
    "type": "object",
    "description": "Beim Anlegen sind `name` und `typ` Pflicht; beim Ändern zählt jedes mitgeschickte Feld.",
    "properties": {
     "typ": {
      "type": "string",
      "enum": [
       "cuvio",
       "direkt"
      ],
      "description": "`cuvio` = über die Cuvio-Partnerschaft, `direkt` = eigener Vertrag."
     },
     "name": {
      "type": "string"
     },
     "bundesland": {
      "type": "string",
      "description": "Länderkürzel wie im ELSTER-Header.",
      "example": "NW"
     },
     "extern_ref": {
      "type": "string",
      "description": "Ihre eigene Id für diesen Arbeitgeber."
     },
     "betriebsnummer": {
      "type": "string",
      "description": "Betriebsnummer der Bundesagentur für Arbeit (8-stellig)."
     },
     "steuernummer": {
      "type": "string",
      "description": "13-stellige bundeseinheitliche Steuernummer."
     },
     "finanzamt_nr": {
      "type": "string",
      "description": "Bundesfinanzamtsnummer (4-stellig)."
     },
     "uv_mitgliedsnr": {
      "type": "string"
     },
     "uv_bg_ik": {
      "type": "string"
     },
     "uv_unternehmensnummer": {
      "type": "string",
      "description": "Unternehmensnummer beim UV-Träger. Wird vom Stammdatenabruf bevorzugt vor `uv_mitgliedsnr` gelesen."
     },
     "uv_bbnr": {
      "type": "string",
      "description": "Betriebsnummer des UV-Trägers; bevorzugt vor `uv_bg_ik`."
     },
     "uv_pin": {
      "type": "string",
      "description": "Zugangskennung für den UV-Stammdatendienst (DSAS/DSSD)."
     },
     "uv_arbeitgeber_ist_traeger": {
      "type": "boolean",
      "description": "Der Arbeitgeber ist selbst ein Unternehmen eines UV-Trägers (Anlage 19c). Dann gilt UV-Grund A07, und es findet **kein** Stammdatenabruf statt. Trifft auf gewöhnliche Betriebe nicht zu; steht in keiner amtlichen Liste und ist deshalb ein Stammdatum."
     },
     "umlage_u1_teilnahme": {
      "type": "boolean",
      "description": "Nimmt der Betrieb am U1-Verfahren teil (≤ 30 Mitarbeiter)?"
     },
     "erstattungssatz_u1": {
      "type": "number",
      "description": "Gewählter U1-Erstattungssatz in Prozent."
     },
     "zahltag": {
      "type": "integer",
      "description": "Tag im Monat, an dem ausgezahlt wird."
     },
     "paragraf_23c_vorlaeufig": {
      "type": "string",
      "enum": [
       "vorlaeufig_pflichtig",
       "beitragsfrei"
      ],
      "default": "vorlaeufig_pflichtig",
      "description": "Wie werden arbeitgeberseitige Leistungen (z. B. Zuschuss zum Krankengeld) behandelt,\n**solange der Sozialleistungsträger Brutto und Netto nicht mitgeteilt hat**?\n\n* `vorlaeufig_pflichtig` — voll beitragspflichtig, Korrektur nach der Rückmeldung\n  (Vorgabe; so rechnet die amtliche Lösung)\n* `beitragsfrei` — mit 0 SV-Tagen beitragsfrei, bis die Rückmeldung kommt\n  (Pflichtenheft S. 82 erlaubt das ausdrücklich)\n\nBeide Wege enden am selben Punkt — mit der Rückmeldung wird korrigiert. Der Unterschied\nist, wer bis dahin in Vorleistung geht.\n"
     },
     "teilmonatsmethode": {
      "type": "string",
      "enum": [
       "dreissigstel",
       "kalendertage"
      ],
      "default": "dreissigstel",
      "description": "Wie wird das Gehalt aufgeteilt, wenn jemand mitten im Monat ein- oder austritt?\n\n* `dreissigstel` — Gehalt ÷ 30 × SV-Tage (Vorgabe)\n* `kalendertage` — Gehalt ÷ tatsächliche Tage des Monats × bezahlte Kalendertage\n\nBeispiel Eintritt am 16.10. bei 3.100,00 € Monatsgehalt: 1.653,33 € nach\nDreißigsteln, 1.600,00 € nach Kalendertagen.\n\n⚠️ Das ist eine **arbeitsrechtliche** Frage; welches Verfahren gilt, steht im\nArbeitsvertrag. Das Pflichtenheft schreibt 1/30 nur für die\n**Beitragsbemessungsgrenze** vor — die bleibt in beiden Fällen unberührt, und auch die\nSV-Tage sind immer Dreißigstel.\n"
     },
     "aag_zahlungsweg": {
      "type": "string",
      "enum": [
       "ueberweisung",
       "verrechnung",
       "gutschrift"
      ],
      "description": "Wie die Umlagekasse die AAG-Erstattung leistet (DBBV UEBVER). Ohne Angabe gilt der\namtliche Regelfall Überweisung.\n"
     },
     "aag_umlagepflicht": {
      "type": "integer",
      "nullable": true,
      "enum": [
       0,
       1
      ],
      "description": "Nimmt der Arbeitgeber am **Ausgleichsverfahren U1/U2** teil? `null`/`1` ist der\nRegelfall; `0` nur für die nach **§ 11 AAG** ausgenommenen Arbeitgeber (Bund, Länder,\nGemeinden und weitere öffentliche Arbeitgeber).\n\n⚠️ Das ist NICHT `umlage_u1_teilnahme`: jene hängt an der Betriebsgröße\n(§ 1 Abs. 1 AAG, i. d. R. ≤ 30 Arbeitnehmer), am **U2-Verfahren nimmt jeder\nArbeitgeber teil** (§ 1 Abs. 2 AAG). ⚠️ Privathaushalte sind hier NICHT ausgenommen —\nfür sie zieht die Minijob-Zentrale U1 und U2 ein.\n"
     },
     "insolvenzgeldumlage_frei": {
      "type": "integer",
      "nullable": true,
      "enum": [
       0,
       1
      ],
      "description": "Befreiung von der **Insolvenzgeldumlage** nach § 358 Abs. 1 S. 2 SGB III: öffentlicher\nDienst (soweit ein Insolvenzverfahren unzulässig ist) und **Privathaushalte**.\n`null`/`0` = umlagepflichtig (Regelfall).\n\n⚠️ Ein anderer Kreis als bei `aag_umlagepflicht` — die beiden fallen nur beim\nöffentlichen Dienst zusammen.\n"
     },
     "betriebsstaette_id": {
      "type": "integer",
      "nullable": true,
      "description": "Der **Beschäftigungsbetrieb** (Mig. 170, Kriterien ec586c06 · e0b8a69d). `null` =\nHauptbetrieb des Mandanten — der Regelfall; gepflegt wird nur, wer in einer ANDEREN\nBetriebsstätte arbeitet. Die Meldung trägt dann deren Betriebsnummer als **BBNRVU**,\nwährend die **HABBNR** die des Unternehmens bleibt.\n"
     },
     "rechtskreis": {
      "type": "string",
      "nullable": true,
      "enum": [
       "W",
       "O"
      ],
      "description": "Rechtskreis der Betriebsstätte (`W` alte Länder, `O` Beitrittsgebiet). `null` = aus dem\nBundesland abgeleitet — für 15 der 16 Länder eindeutig; bei einer **Berliner**\nBetriebsstätte ist die Angabe nötig, weil die Grenze historisch durch die Stadt lief.\n\n⚠️ Im Meldefeld KENNZRK ist der Rechtskreis ab dem 01.01.2025 Grundstellung; in den\n**Entgeltunterlagen** bleibt er zu führen.\n"
     },
     "umlage_ausnahme_grund": {
      "type": "string",
      "nullable": true,
      "maxLength": 200,
      "description": "Begründung der Umlage-Ausnahme (welcher Tatbestand, seit wann). Für die\nBetriebsprüfung: eine Ausnahme ohne Begründung sieht im Nachhinein wie ein Versehen aus.\n"
     },
     "ansprechpartner_anrede": {
      "type": "string",
      "enum": [
       "M",
       "W",
       "X",
       "D"
      ],
      "description": "Anrede der Ansprechperson im Meldeverfahren (DXBD, ab 01.01.2027 Pflicht).\n⚠️ Ohne Vorgabewert — eine Anrede ist eine Aussage über einen Menschen; fehlt sie,\nentsteht keine Betriebsdatenmeldung, sondern eine benannte Hürde.\n"
     },
     "postanschrift_name_1": {
      "type": "string",
      "maxLength": 30,
      "description": "Abweichende Postanschrift — Name. ⚠️ **Ausschließlich eine Anschrift des ARBEITGEBERS**;\nPostanschriften Dritter (Steuerberater, Lohnbüro) sind in DSBD und DXBD unzulässig und\nwerden anhand von Signalwörtern erkannt.\n"
     },
     "postanschrift_name_2": {
      "type": "string",
      "maxLength": 30
     },
     "postanschrift_name_3": {
      "type": "string",
      "maxLength": 30
     },
     "postanschrift_plz": {
      "type": "string",
      "maxLength": 10
     },
     "postanschrift_ort": {
      "type": "string"
     },
     "postanschrift_strasse": {
      "type": "string"
     },
     "postanschrift_hausnummer": {
      "type": "string",
      "maxLength": 10
     },
     "postanschrift_zusatz": {
      "type": "string",
      "maxLength": 30
     },
     "postanschrift_postfach": {
      "type": "string",
      "maxLength": 10
     },
     "postanschrift_land": {
      "type": "string",
      "maxLength": 2,
      "description": "Länderkennzeichen bei Auslandsanschrift."
     },
     "postanschrift_art": {
      "type": "string",
      "enum": [
       "1",
       "2",
       "3",
       "4"
      ],
      "description": "Art der Postanschrift (amtlicher Schlüssel). ⚠️ Ohne ihn wird die Postanschrift **nicht**\nübertragen — eine unvollständige Anschrift ist schlechter als keine. Bei\n`dxbd_sondersachverhalt` 1 oder 2 ist die Postanschrift Pflicht.\n"
     },
     "dienstleister_name_1": {
      "type": "string",
      "maxLength": 30,
      "description": "Name des **Dienstleisters**, der die Entgeltabrechnung im Auftrag führt (DSAK-Baustein\nDBDL). ⚠️ NICHT dasselbe wie `abrechnungsstelle_bbnr`: die sagt, wer SENDET; hier\nsteht, WER abrechnet — ein Steuerberater ohne eigene Betriebsnummer ist Dienstleister\nund keine Abrechnungsstelle. Eine Änderung löst einen DSAK mit Abgabegrund 02 aus\n(Pflichtenheft S. 139).\n"
     },
     "dienstleister_name_2": {
      "type": "string",
      "maxLength": 30
     },
     "dienstleister_name_3": {
      "type": "string",
      "maxLength": 30
     },
     "dienstleister_ansprechpartner_name": {
      "type": "string",
      "maxLength": 30,
      "description": "Ansprechpartner beim Dienstleister — ein anderer Mensch als der des Arbeitgebers."
     },
     "dienstleister_ansprechpartner_telefon": {
      "type": "string",
      "maxLength": 20
     },
     "dienstleister_ansprechpartner_email": {
      "type": "string",
      "maxLength": 70
     },
     "dienstleister_plz": {
      "type": "string",
      "maxLength": 10
     },
     "dienstleister_ort": {
      "type": "string",
      "maxLength": 34
     },
     "dienstleister_strasse": {
      "type": "string",
      "maxLength": 33
     },
     "dienstleister_hausnummer": {
      "type": "string",
      "maxLength": 9
     },
     "dienstleister_postfach": {
      "type": "string",
      "maxLength": 10
     },
     "dienstleister_land": {
      "type": "string",
      "maxLength": 3,
      "description": "Länderkennzeichen nach Anlage 8."
     },
     "dienstleister_geloescht_am": {
      "type": "string",
      "format": "date",
      "description": "Tag, an dem der Dienstleister entfallen ist. ⚠️ Ein entfallener Dienstleister wird\n**gemeldet** (DBDL mit Kennzeichen Löschen „J\"), nicht stillschweigend entfernt —\nsonst führte die Kasse weiter einen Ansprechpartner, den es nicht mehr gibt.\n"
     },
     "dxbd_sondersachverhalt": {
      "type": "string",
      "enum": [
       "1",
       "2",
       "3",
       "4"
      ],
      "description": "Kennzeichen_Sondersachverhalte des DXBD. `1` = Arbeitgeber ohne Standort in\nDeutschland — dann ist die abweichende Postanschrift Pflicht.\n"
     },
     "dxbd_rechtsform": {
      "type": "string",
      "maxLength": 5,
      "description": "Rechtsformschlüssel der BA-Codeliste (fünfstellig, DXBD). ⚠️ NICHT dasselbe wie\n`rechtsform`: das ist der dreistellige Schlüssel des DSBD-Verfahrens.\n"
     },
     "dxbd_absendernummer": {
      "type": "string",
      "maxLength": 8,
      "description": "BBNR, von der der DXBD technisch übermittelt wird (Verfahrensanforderung DXBD/DXBE\nZiffer 5.2.1.1). ⚠️ NICHT dasselbe wie `abrechnungsstelle_bbnr`: beide sind eigene\nSteuerungsdaten mit VERSCHIEDENEN Abgabegründen — eine Änderung der Abrechnungsstelle\nverlangt A01 „Bestandsmeldung\", die alleinige Änderung der Absendernummer A09\n„Absenderänderung\". Leer ist der Normalfall; dann gilt die eigene Betriebsnummer, die\nnach der Verfahrensanforderung ohnehin Vorrang hat. Gesetzt nur im Ausnahmefall des\n§ 18n Abs. 2 SGB IV.\n"
     },
     "wukl": {
      "type": "string",
      "maxLength": 5,
      "description": "Wirtschaftsunterklasse des Beschäftigungsbetriebs (DXBD; über A05 abfragbar)."
     },
     "aag_verwendungszweck": {
      "type": "string",
      "maxLength": 27,
      "description": "Verwendungszweck der Erstattung (DBBV). ⚠️ Darf KEINE personenbezogenen Daten tragen\n(Name, Versicherungs-, Personalnummer) — er läuft durch den Zahlungsverkehr. Ein\nunzulässiger Text wird beim Bauen des Antrags sichtbar durch „Erstattung AAG\" ersetzt.\n"
     },
     "anschrift_strasse": {
      "type": "string"
     },
     "anschrift_hausnummer": {
      "type": "string"
     },
     "anschrift_plz": {
      "type": "string"
     },
     "anschrift_ort": {
      "type": "string"
     },
     "ansprechpartner_name": {
      "type": "string"
     },
     "ansprechpartner_telefon": {
      "type": "string"
     },
     "ansprechpartner_email": {
      "type": "string"
     },
     "rechtsform": {
      "type": "string",
      "description": "Schlüssel der Rechtsform (DSBD-Katalog)."
     },
     "rechtsform_ergaenzung": {
      "type": "string"
     },
     "abrechnungsstelle_bbnr": {
      "type": "string",
      "description": "Betriebsnummer der Abrechnungsstelle (Steuerberater u. Ä.), mit Prüfziffer. Geht in euBP (DSST BBNRAS), DSBD (BBNR-AS) und löst beim DXBD bei AUSSCHLIESSLICHER Änderung eine Bestandsmeldung A01 aus. Leer = keine Abrechnungsstelle, dann gilt die eigene."
     },
     "deuev_systembeginn": {
      "type": "string",
      "format": "date",
      "nullable": true,
      "description": "DEÜV-Systembeginn (Migration 088, Pflichtenheft 0104 S. 127): erster Tag, ab dem Lohnfluss die DEÜV-Meldungen erstattet. Eintritte davor → Anmeldung GD 13 zu diesem Tag (POST /deuev/bestandsanmeldung); Läufe davor lösen keine DEÜV-Meldungen aus; Rückrechnungen in Monate davor sind gesperrt."
     },
     "kug_bewilligung_von": {
      "type": "string",
      "format": "date",
      "description": "Beginn des von der Agentur für Arbeit bewilligten Arbeitsausfalls. Die Bewilligung trifft den BETRIEB — die einzelne Person hat keinen eigenen Bewilligungszeitraum. Kurzarbeits-Bewegungen außerhalb dieses Zeitraums werden abgewiesen."
     },
     "kug_bewilligung_bis": {
      "type": "string",
      "format": "date"
     },
     "kug_aktenzeichen": {
      "type": "string",
      "description": "Kug-Aktenzeichen bzw. Stammnummer der Agentur für Arbeit."
     },
     "insolvenz_ereignis": {
      "type": "string",
      "format": "date",
      "description": "Tag des Insolvenzereignisses (§ 165 SGB III). Er trifft den Betrieb und löst je Person die DEÜV-Meldekette aus: freigestellte Beschäftigte bekommen GD 71 zum Vortag, danach die Jahresmeldung GD 70 und zum rechtlichen Ende GD 72; weiterbeschäftigte eine gewöhnliche Abmeldung GD 33. Die Freistellung selbst steht am Mitarbeiter (`insolvenz_freistellung_ab`)."
     },
     "inso_einzugsstelle_ik": {
      "type": "string",
      "description": "Einzugsstelle (IK) für Beschäftigte OHNE Krankenkasse. Privat Versicherte schulden die Insolvenzgeldumlage nach § 358 SGB III, haben aber keine Kasse; zuständig ist die vom Arbeitgeber gewählte Einzugsstelle (§ 28i Satz 2 SGB IV i. V. m. § 175 Abs. 3 Satz 2 SGB V). Ohne diesen Wert entsteht für den Monat KEIN Beitragsnachweis — bewusst, denn ein Nachweis ohne diese Beiträge wäre zu klein und fiele erst der Betriebsprüfung auf."
     },
     "zuschlagsregeln": {
      "type": "object",
      "description": "Betriebliche Regeln für SFN-Zuschläge."
     },
     "status": {
      "type": "string",
      "enum": [
       "aktiv",
       "ruhend",
       "beendet"
      ],
      "description": "Betriebsstatus. **`beendet`** = vollständige Einstellung des Beschäftigungsbetriebs → DSBD mit\nBeendigungskennzeichen „B\" (Pflichtenheft S. 146). Wird nur die Abrechnung in diesem Programm\nbeendet (Mandatsabgabe, Systemwechsel) und der Betrieb fortgesetzt, ist `ruhend` richtig.\n"
     },
     "datum_ereignis": {
      "type": "string",
      "format": "date",
      "description": "Ereignisdatum für den DSBD (Tag, ab dem die Änderung gilt bzw. Tag der vollständigen Einstellung). **Nicht vorbelegt** (S. 145) — ohne Angabe entsteht eine Hürde statt eines Entwurfs."
     },
     "beendigung_bestaetigt": {
      "type": "boolean",
      "description": "Sicherheitsabfrage (S. 153, Mechanismus C) — Pflicht bei `status = beendet`."
     },
     "beendigung_trotz_offener_anmeldungen": {
      "type": "boolean",
      "description": "Plausibilisierungshinweis (S. 153, Mechanismus B) ausdrücklich übergehen, wenn noch Beschäftigte angemeldet sind."
     },
     "systemwechsel": {
      "type": "boolean",
      "description": "**Pflicht, sobald eine Betriebsnummer erstmals erfasst wird** (Anlegen oder erster PATCH mit\nBetriebsnummer): Liegt ein Systemwechsel oder eine Ersterfassung wegen Dienstleisterwechsels vor\n(Pflichtenheft S. 142)? Bei `true` entsteht der DSBD mit Grund 06 — dann ist `datum_ereignis`\n(Tag der Übernahme) ebenfalls Pflicht.\n"
     }
    }
   },
   "MandantKurz": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "typ": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "bundesland": {
      "type": "string"
     },
     "extern_ref": {
      "type": [
       "string",
       "null"
      ]
     },
     "betriebsnummer": {
      "type": [
       "string",
       "null"
      ]
     },
     "status": {
      "type": "string"
     }
    }
   },
   "Mandant": {
    "description": "Vollstaendige Stammdaten. Die Antwort fuehrt **alle** aenderbaren Felder — auch die\nleeren. Wer nur die gefuellten liefert, kann eine Oberflaeche nicht bedienen: sie\nkoennte ein leeres Feld nicht von einem unbekannten unterscheiden.\n",
    "allOf": [
     {
      "$ref": "#/components/schemas/MandantKurz"
     },
     {
      "type": "object",
      "properties": {
       "partner_id": {
        "type": "integer"
       },
       "steuernummer": {
        "type": [
         "string",
         "null"
        ]
       },
       "finanzamt_nr": {
        "type": [
         "string",
         "null"
        ],
        "description": "Bundesfinanzamtsnummer (BUFA)."
       },
       "uv_mitgliedsnr": {
        "type": [
         "string",
         "null"
        ]
       },
       "uv_bg_ik": {
        "type": [
         "string",
         "null"
        ]
       },
       "uv_unternehmensnummer": {
        "type": [
         "string",
         "null"
        ]
       },
       "uv_bbnr": {
        "type": [
         "string",
         "null"
        ]
       },
       "uv_pin": {
        "type": [
         "string",
         "null"
        ]
       },
       "uv_arbeitgeber_ist_traeger": {
        "type": [
         "boolean",
         "integer",
         "null"
        ]
       },
       "umlage_u1_teilnahme": {
        "type": [
         "boolean",
         "null"
        ]
       },
       "aag_umlagepflicht": {
        "type": [
         "boolean",
         "integer",
         "null"
        ]
       },
       "insolvenzgeldumlage_frei": {
        "type": [
         "boolean",
         "integer",
         "null"
        ]
       },
       "rechtskreis": {
        "type": [
         "string",
         "null"
        ]
       },
       "betriebsstaette_id": {
        "type": [
         "integer",
         "null"
        ]
       },
       "umlage_ausnahme_grund": {
        "type": [
         "string",
         "null"
        ]
       },
       "erstattungssatz_u1": {
        "type": [
         "number",
         "null"
        ]
       },
       "zahltag": {
        "type": [
         "integer",
         "null"
        ]
       },
       "teilmonatsmethode": {
        "type": "string",
        "enum": [
         "dreissigstel",
         "kalendertage"
        ]
       },
       "paragraf_23c_vorlaeufig": {
        "type": "string",
        "enum": [
         "vorlaeufig_pflichtig",
         "beitragsfrei"
        ]
       },
       "anschrift_strasse": {
        "type": [
         "string",
         "null"
        ]
       },
       "anschrift_hausnummer": {
        "type": [
         "string",
         "null"
        ]
       },
       "anschrift_plz": {
        "type": [
         "string",
         "null"
        ]
       },
       "anschrift_ort": {
        "type": [
         "string",
         "null"
        ]
       },
       "ansprechpartner_name": {
        "type": [
         "string",
         "null"
        ]
       },
       "ansprechpartner_telefon": {
        "type": [
         "string",
         "null"
        ]
       },
       "ansprechpartner_email": {
        "type": [
         "string",
         "null"
        ]
       },
       "rechtsform": {
        "type": [
         "string",
         "null"
        ]
       },
       "rechtsform_ergaenzung": {
        "type": [
         "string",
         "null"
        ]
       },
       "abrechnungsstelle_bbnr": {
        "type": [
         "string",
         "null"
        ],
        "description": "Betriebsnummer der Abrechnungsstelle (Mig. 084)."
       },
       "deuev_systembeginn": {
        "type": "string",
        "format": "date",
        "nullable": true,
        "description": "DEÜV-Systembeginn (Migration 088, Pflichtenheft 0104 S. 127): erster Tag, ab dem Lohnfluss die DEÜV-Meldungen erstattet. Eintritte davor → Anmeldung GD 13 zu diesem Tag (POST /deuev/bestandsanmeldung); Läufe davor lösen keine DEÜV-Meldungen aus; Rückrechnungen in Monate davor sind gesperrt."
       },
       "betrieb_beendet_am": {
        "type": [
         "string",
         "null"
        ],
        "format": "date",
        "description": "Tag der vollständigen Einstellung der Betriebstätigkeit (DXBD A03) — nur über POST /dxbd/beendigung setzbar."
       },
       "kug_bewilligung_von": {
        "type": [
         "string",
         "null"
        ],
        "format": "date"
       },
       "kug_bewilligung_bis": {
        "type": [
         "string",
         "null"
        ],
        "format": "date"
       },
       "kug_aktenzeichen": {
        "type": [
         "string",
         "null"
        ]
       },
       "insolvenz_ereignis": {
        "type": [
         "string",
         "null"
        ],
        "format": "date"
       },
       "inso_einzugsstelle_ik": {
        "type": [
         "string",
         "null"
        ]
       },
       "ansprechpartner_anrede": {
        "type": [
         "string",
         "null"
        ]
       },
       "dxbd_sondersachverhalt": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_name_1": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_name_2": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_name_3": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_plz": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_ort": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_strasse": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_hausnummer": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_zusatz": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_postfach": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_land": {
        "type": [
         "string",
         "null"
        ]
       },
       "postanschrift_art": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_name_1": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_name_2": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_name_3": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_ansprechpartner_name": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_ansprechpartner_telefon": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_ansprechpartner_email": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_plz": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_ort": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_strasse": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_hausnummer": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_postfach": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_land": {
        "type": [
         "string",
         "null"
        ]
       },
       "dienstleister_geloescht_am": {
        "type": [
         "string",
         "null"
        ],
        "format": "date"
       },
       "dxbd_rechtsform": {
        "type": [
         "string",
         "null"
        ],
        "maxLength": 5
       },
       "dxbd_absendernummer": {
        "type": [
         "string",
         "null"
        ],
        "maxLength": 8
       },
       "wukl": {
        "type": [
         "string",
         "null"
        ],
        "maxLength": 5
       },
       "aag_zahlungsweg": {
        "type": [
         "string",
         "null"
        ],
        "enum": [
         "ueberweisung",
         "verrechnung",
         "gutschrift",
         null
        ],
        "description": "Zahlungsweg der AAG-Erstattung (DBBV UEBVER); `null` = Überweisung."
       },
       "aag_verwendungszweck": {
        "type": [
         "string",
         "null"
        ],
        "maxLength": 27
       },
       "zuschlagsregeln": {
        "type": [
         "object",
         "null"
        ]
       },
       "bank": {
        "description": "Aktive Auftraggeber-Bankverbindung; `null`, solange keine gesetzt ist.",
        "oneOf": [
         {
          "type": "null"
         },
         {
          "type": "object",
          "properties": {
           "kontoinhaber": {
            "type": "string"
           },
           "iban": {
            "type": "string"
           },
           "bic": {
            "type": [
             "string",
             "null"
            ]
           },
           "zweck_praefix": {
            "type": [
             "string",
             "null"
            ]
           }
          }
         }
        ]
       }
      }
     }
    ]
   },
   "MitarbeiterEingabe": {
    "type": "object",
    "description": "Stamm- und Zeitscheiben-Felder in einem Objekt. Stammdaten gelten dauerhaft,\nZeitscheiben-Felder ab `gueltig_ab`.\n",
    "properties": {
     "gueltig_ab": {
      "type": "string",
      "format": "date",
      "description": "Beginn der Zeitscheibe. Beim Anlegen optional (dann `eintritt`), beim Ändern Pflicht, sobald ein Zeitscheiben-Feld dabei ist."
     },
     "extern_ref": {
      "type": "string"
     },
     "vorname": {
      "type": "string"
     },
     "nachname": {
      "type": "string"
     },
     "geburtsdatum": {
      "type": "string",
      "format": "date"
     },
     "geburtsname": {
      "type": "string"
     },
     "geschlecht": {
      "type": "string",
      "enum": [
       "m",
       "w",
       "d",
       "x"
      ]
     },
     "anschrift_strasse": {
      "type": "string"
     },
     "anschrift_hausnummer": {
      "type": "string"
     },
     "anschrift_plz": {
      "type": "string"
     },
     "anschrift_ort": {
      "type": "string"
     },
     "anschrift_land": {
      "type": "string"
     },
     "staatsangehoerigkeit": {
      "type": "string"
     },
     "sv_nummer": {
      "type": "string",
      "description": "Versicherungsnummer der Rentenversicherung."
     },
     "insolvenz_freistellung_ab": {
      "type": "string",
      "format": "date",
      "description": "Im Insolvenzfall ab diesem Tag freigestellt. Leer heißt weiterbeschäftigt — und dieser Unterschied entscheidet die Meldung: Freigestellte bekommen GD 71/70/72, Weiterbeschäftigte eine gewöhnliche Abmeldung GD 33. Wirkt nur zusammen mit `insolvenz_ereignis` am Mandanten."
     },
     "rentenbezieher": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Bezieht eine Rente (euBP DSAN KENNZRBZ, Mussfeld J/N). null = nicht erfasst — dann entsteht keine euBP-Lieferung, sondern eine Hürde, die die Person nennt; aus der Beitragsgruppe ableitbar ist nur der Altersvollrentner mit RV „3\" (Mig. 083)."
     },
     "steuer_id": {
      "type": "string",
      "description": "Steuer-Identifikationsnummer (11-stellig)."
     },
     "iban": {
      "type": "string"
     },
     "bic": {
      "type": "string"
     },
     "eintritt": {
      "type": "string",
      "format": "date"
     },
     "austritt": {
      "type": "string",
      "format": "date"
     },
     "personengruppe": {
      "type": "string",
      "description": "Amtlicher Personengruppenschlüssel, z. B. `101`, `106` (Werkstudent), `109` (geringfügig).",
      "example": "101"
     },
     "taetigkeitsschluessel": {
      "type": "string",
      "description": "9-stellig; wird gegen den amtlichen Katalog geprüft.",
      "example": "821012911"
     },
     "taetigkeitsbezeichnung": {
      "type": "string",
      "maxLength": 120,
      "example": "Pflegefachkraft",
      "description": "**Tätigkeit im Klartext** für die Einzelaufstellung der Beitragsabrechnung-UV\n(Pflichtenheft Unfallversicherung 0115, S. 412 Nr. 3a). ⚠️ Ausdrücklich „keine\nÜbernahme aus dem Tätigkeitsschlüssel\": der neunstellige BA-Schlüssel ist eine\nKlassifikation, kein Berufsname. Leer heißt „nicht erfasst\" — im Dokument steht dann\nein Strich, keine erfundene Bezeichnung (Mig. 162).\n"
     },
     "beitragsgruppe": {
      "type": "string",
      "description": "Beitragsgruppenschlüssel KV/RV/AV/PV, z. B. `1111` oder `0100` (Werkstudent).",
      "example": "1111"
     },
     "kasse_ik": {
      "type": "string",
      "description": "Institutionskennzeichen der Krankenkasse."
     },
     "steuerklasse": {
      "type": "integer",
      "minimum": 1,
      "maximum": 6
     },
     "faktor": {
      "type": "number",
      "description": "Faktorverfahren in Steuerklasse IV."
     },
     "kinderfreibetraege": {
      "type": "number"
     },
     "kist_merkmal": {
      "type": "string",
      "description": "Kirchensteuer-Merkmal, z. B. `rk`, `ev`."
     },
     "pv_kinder": {
      "type": "integer",
      "description": "Zahl der Kinder unter 25 — steuert die Abschläge in der Pflegeversicherung."
     },
     "vertrag": {
      "type": "string",
      "enum": [
       "gehalt",
       "stundenlohn",
       "sonstiges"
      ],
      "description": "**Entlohnungsform**, nicht Vertragsdauer: `gehalt` (fester Monatsbetrag),\n`stundenlohn` (Satz mal geleistete Stunden) oder `sonstiges` (Akkord, Stücklohn,\nProvision). Steuert, welches Feld die Engine heranzieht — `grundgehalt_cent` oder\n`stundenlohn_cent`.\n\n⚠️ Bei `sonstiges` gibt es **weder** ein Grundgehalt **noch** einen Stundensatz: der\nBetrag steht an der Bewegung und wird nicht gerechnet. Eine Bewegung ohne Betrag ergibt\neinen benannten Hinweis, keine geschätzte Zahlung. Die Entgeltfortzahlung im\nKrankheitsfall entsteht wie beim Stundenlohn aus dem Durchschnitt der Referenzmonate\n(§ 4 Abs. 1a EFZG).\n\nDie Entlohnungsform bestimmt zugleich das Feld **ENTGART** der Entgeltbescheinigung\n(1 = Stundenlohn · 2 = festes Monatsentgelt · 3 = Sonstiges). Sie entscheidet damit\nmit, ob der Datenbaustein Arbeitszeit (DBZA) entsteht.\n⚠️ Die Spalte ist ein ENUM. Ein anderer Wert wurde bis 08.08.2026 als „Data\ntruncated\" mit HTTP 500 quittiert; heute antwortet die API mit 422 und nennt das Feld.\n"
     },
     "wochenstunden": {
      "type": "number"
     },
     "arbeitszeitmodell": {
      "type": [
       "string",
       "null"
      ],
      "description": "Wertguthaben-Arbeitszeitmodell § 7 Abs. 1a SGB IV (EEL, DBAL ARBZEITMOD)."
     },
     "pv_elterneigenschaft": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Elterneigenschaft nach § 55 Abs. 3 SGB XI. ⚠️ **Dreiwertig:** `true`/`1` = Elternteil\n(kein Zuschlag für Kinderlose, lebenslang und unabhängig vom Alter der Kinder),\n`false`/`0` = kinderlos, `null` = nicht bekannt. `null` ist ausdrücklich **nicht**\n„kinderlos\": ohne Nachweis wird der Zuschlag weder unterstellt noch erlassen.\nEine Angabe hier schlägt die DaBPV-Rückmeldung des BZSt.\n"
     },
     "bei_lkk_versichert": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Versicherung bei der landwirtschaftlichen Krankenkasse (LKK). Dreiwertig, `null` =\nnicht angegeben. Die Personengruppen 112 und 114 setzen sie voraus.\n"
     },
     "hauptberuflich_landwirt": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Hauptberuflich selbständige Erwerbstätigkeit als Landwirt. Dann ist die\nKrankenversicherungspflicht in **dieser** Beschäftigung ausgeschlossen (BGR-KV muss 0\nsein); für den Einzug der RV-/AV-Beiträge ist die LKK zuständig.\n"
     },
     "befristung_wochen": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Voraussichtliche Dauer einer befristeten Beschäftigung. PGS 114 gilt nur bis 26 Wochen."
     },
     "freiwillig_ohne_krankengeld": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "In der LKK freiwillig und **ohne** Anspruch auf Krankengeld versichert. Dann wird der\nBeitrag nicht nach Beitragssatz gerechnet, sondern nach der Beitragsklasse der\nLKK-Satzung — ohne `lkv_beitrag_kv_cent` wird gar nicht gerechnet.\n"
     },
     "lkv_beitrag_kv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Nach Beitragsklasse der LKK-Satzung vorgegebener KV-Beitrag, in Cent."
     },
     "lkv_beitrag_pv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Vorgegebener PV-Beitrag (Zuschlag zum KV-Beitrag der LKK), in Cent."
     },
     "beitragsherabsetzung_ab": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Tag der Antragstellung auf **Beitragsherabsetzung** bei Kurzarbeit (freiwillig\ngesetzlich Versicherte). ⚠️ Ein Datum, kein Kennzeichen: die Wirkung reicht *ab\nAntragstellung bis zum Ende des Kalenderjahres* — und nur in Monaten mit tatsächlichem\nKug-Bezug. Ohne Antrag bleibt es beim Höchstbeitrag aus der Beitragsbemessungsgrenze.\n"
     },
     "pauschsteuer_abgewaelzt": {
      "type": "boolean",
      "default": false,
      "description": "Die **Pauschsteuer wird auf den geringfügig Beschäftigten abgewälzt**\n(§ 40a Abs. 5 in Verbindung mit § 40 Abs. 3 EStG, Migration 138).\n\nSchuldner der pauschalen Lohnsteuer bleibt der Arbeitgeber; die Abwälzung im\nInnenverhältnis ist zulässig, wenn sie vereinbart ist. ⚠️ Sie mindert das\n**Arbeitsentgelt nicht**: beitragspflichtig bleibt der volle Betrag, und die\nPauschsteuer selbst wird weiter vom vollen Entgelt berechnet. Sie ist ein reiner\nNetto-Abzug und mindert zugleich die Arbeitgeberkosten.\n\nZweiwertig mit Vorgabe `false` — wer nichts vereinbart hat, hat nicht abgewälzt.\n"
     },
     "u1_pflicht": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "**Übersteuerung der U1-Umlagepflicht** für diese Person (Pflichtenheft S. 79,\nMigration 140). ⚠️ **Dreiwertig:** `null` heißt *wie im Unternehmen* — nicht „nein\".\n\nDie Regel gilt für den Betrieb, nicht für die Person; es gibt aber Fälle, in denen\nder Anwender sie einzeln setzen muss. Die Übersteuerung wird **verworfen**, wenn im\nUnternehmen überhaupt keine Umlagepflicht besteht — dann trägt die Abrechnung eine\nBegründung, statt still zu rechnen.\n"
     },
     "u2_pflicht": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "**Übersteuerung der U2-Umlagepflicht** für diese Person (Pflichtenheft S. 79,\nMigration 140). ⚠️ Dreiwertig wie `u1_pflicht`; `null` = wie im Unternehmen.\n"
     },
     "saisonarbeitnehmer": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Kennzeichen SAISONARBEITNEHMER im DBME der Anmeldung. Eine Änderung erzeugt Storno + Neuanmeldung."
     },
     "arbeitnehmer_status": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "arbeitnehmer",
       "kein_arbeitnehmer",
       null
      ],
      "description": "Arbeitnehmereigenschaft für die Insolvenzgeldumlage (§ 358 Abs. 1 SGB III). Ein\nbeherrschender Gesellschafter-Geschäftsführer ist keiner. ⚠️ `null` = nicht festgelegt;\ndas Programm entscheidet es nicht, es macht den Fall sichtbar.\n"
     },
     "statuskennzeichen": {
      "type": [
       "string",
       "null"
      ],
      "description": "KENNZSTA im DSME (Angehöriger/Ehegatte/Gesellschafter-Geschäftsführer)."
     },
     "einzugsstelle_ik": {
      "type": [
       "string",
       "null"
      ],
      "description": "Einzugsstelle für Beschäftigte ohne gesetzliche Krankenkasse (privat versichert, versicherungsfrei)."
     },
     "umlagekasse_ik": {
      "type": [
       "string",
       "null"
      ],
      "description": "Vom Arbeitgeber gewählte Umlagekasse (U1/U2), wenn die Krankenkasse keine ist — etwa bei der SVLFG."
     },
     "ausgleichseinrichtung_ik": {
      "type": [
       "string",
       "null"
      ],
      "description": "Ausgleichseinrichtung nach dem AAG, sofern abweichend."
     },
     "kug_leistungssatz": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Kug-Leistungssatz in Prozent, je Zeitraum individuell (eine Nachberechnung muss den damals geltenden treffen)."
     },
     "kv_gesetzlich": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Krankenversicherungsschutz bei kurzfristig Beschäftigten (DSME-Feld KENNZKV, seit 2022\nPflicht bei PGR 110). ⚠️ Dreiwertig — „nicht angegeben\" ist etwas anderes als „privat\".\n"
     },
     "sollarbeitszeit": {
      "type": [
       "number",
       "null"
      ],
      "description": "Tarifliche/vertragliche Sollarbeitszeit — Grundlage des Lohnnachweises beim UV-Beitragsmaßstab „Arbeitsstunden\"."
     },
     "sollarbeitszeit_einheit": {
      "type": [
       "string",
       "null"
      ],
      "description": "Einheit der Sollarbeitszeit (Woche/Monat/Jahr)."
     },
     "urlaubstage": {
      "type": "number"
     },
     "schwerbehinderung": {
      "type": "boolean"
     },
     "mehrfachbeschaeftigt": {
      "type": "boolean"
     },
     "privat_kv": {
      "type": "boolean",
      "description": "Privat krankenversichert. Setzt in der Lohnsteuer das Merkmal PKV und schaltet bei\ngeringfügig Beschäftigten die 13-%-Pauschale ab.\n"
     },
     "pkv_beitrag_cent": {
      "type": "integer",
      "description": "Monatsbeitrag zur privaten Kranken-/Pflegeversicherung, Grundlage des Zuschusses."
     },
     "keine_rv": {
      "type": "boolean",
      "description": "rentenversicherungsfrei"
     },
     "arbeitstage_muster": {
      "type": "string",
      "pattern": "^1?2?3?4?5?6?7?$",
      "example": "12345",
      "description": "Die Arbeitstage als **aufsteigende Ziffernfolge** der Wochentage, 1 = Montag bis\n7 = Sonntag: `12345` = Montag bis Freitag, `135` = Montag, Mittwoch, Freitag. Jeder\nTag höchstens einmal und in dieser Reihenfolge — so verlangt es die CHECK-Regel der\nDatenbank. Grundlage der Arbeits- und Ausfalltage.\n"
     },
     "gefahrtarifstelle": {
      "type": "string",
      "description": "Aus dem Veranlagungsbescheid der Berufsgenossenschaft (§ 159 Abs. 1 SGB VII). Geht in\nden DSME (Feld GT_STELLE) und in die UV-Jahresmeldung; ohne sie ist kein Lohnnachweis\nmöglich.\n"
     },
     "freiwillig_gkv": {
      "type": "boolean",
      "default": false,
      "description": "Freiwilliges Mitglied der gesetzlichen Krankenversicherung als **Selbstzahler** — der\nBeschäftigte zahlt seine Beiträge selbst und bekommt den Zuschuss nach § 257 Abs. 1 SGB V.\n\n⚠️ Nicht dasselbe wie das **Firmenzahlerverfahren** (Beitragsgruppe KV `9`): dort führt der\nArbeitgeber die vollen Beiträge ab und zahlt **keinen** Zuschuss. Beides zusammen ist ein\nWiderspruch; der Lohnlauf meldet ihn und zahlt nichts.\n"
     },
     "freiwillig_kv_beitrag_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Tatsächlicher monatlicher KV-Beitrag des Beschäftigten — der Zuschuss beträgt höchstens die Hälfte davon."
     },
     "freiwillig_pv_beitrag_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Tatsächlicher monatlicher PV-Beitrag. Ohne diese Angabe entfällt der Zuschuss zur Pflegeversicherung."
     },
     "pkv_pv_beitrag_cent": {
      "type": [
       "integer",
       "null"
      ],
      "minimum": 0,
      "description": "Der **private Pflege**versicherungsbeitrag, getrennt vom Gesamtbeitrag `pkv_beitrag_cent`.\nOhne ihn wird der Gesamtbeitrag als KV-Beitrag angesetzt und der PV-Zuschuss entfällt —\ndas ist die vorsichtige, aber tendenziell zu niedrige Variante.\n"
     },
     "zuschuss_art": {
      "type": "string",
      "enum": [
       "entgelt",
       "bbg"
      ],
      "default": "entgelt",
      "description": "Art der Bezuschussung bei freiwilliger GKV: am **tatsächlichen Entgelt** (gekappt auf die\nBeitragsbemessungsgrenze) oder immer an der **BBG** — dann der Höchstzuschuss.\n\n⚠️ Ein Stammdatum, keine Rechenfrage: in jedem Teilentgelt-Monat kommt je nach Wahl ein\nanderer Betrag heraus.\n"
     },
     "rentenart": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "altersvollrente",
       "berufsstaendisch",
       "beamtenrechtlich",
       "altersteilrente",
       "teilversorgung",
       "altersvollrente_nicht_eu",
       "erwerbsminderung_voll",
       null
      ],
      "description": "Kennzeichen Rentenart nach **Anlage 04a** zum Pflichtenheft. `null` = kein Rentenbezug.\n\n⚠️ Sobald eine **Vollrente wegen Alters** oder eine **Vollversorgung** hier steht, ist\n`verzicht_rv_freiheit` ausdrücklich zu beantworten; bei allen anderen Werten muss es in\nGrundstellung bleiben (Prüfkriterien 001/002).\n\n⚠️ Bei `altersteilrente`, `teilversorgung`, `altersvollrente_nicht_eu` und\n`erwerbsminderung_voll` sind die **Personengruppen 119 und 120 unzulässig** — eine\nAltersvollrente eines Nicht-EU/EWR/SVA-Staates ist der deutschen nicht gleichgestellt\n(Prüfkriterium 012).\n\n⚠️ Liegen mehrere Arten vor, gilt die in dieser Aufzählung **weiter oben stehende**.\n"
     },
     "rentenbeginn": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Rentenbeginn laut Rentenbescheid — geht in die Prüfkriterien 009 und 010 ein."
     },
     "anpassungsgeld_bergbau": {
      "type": "boolean",
      "default": false,
      "description": "Anpassungsgeld für entlassene Arbeitnehmer des Bergbaus vor Rentenbeginn bezogen.\n\n⚠️ Dann gilt die Regelaltersgrenze schon in dem Monat als erreicht, in dem das\n**65. Lebensjahr** vollendet wurde — das **verschiebt alle Stichtagsprüfungen**.\n"
     },
     "in_ausbildung": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Steht die Person in **Berufsausbildung**? `null` = keine Angabe (keine Prüfung).\n\nBei `true` hat die Ausbildungs-Personengruppe Vorrang (102 Auszubildende ·\n105 Praktikanten · 121/122 außerbetriebliche Ausbildung); eine andere Personengruppe\nführt zu einem Prüfketten-Befund. ⚠️ Der Tätigkeitsschlüssel trägt den\nAusbildungs-**Abschluss**, nicht den laufenden Ausbildungsvertrag — daraus lässt sich\ndas Merkmal nicht ableiten.\n"
     },
     "knappschaftlich_rv": {
      "type": [
       "boolean",
       "integer",
       "null"
      ],
      "description": "Beschäftigung in einem knappschaftlichen Betrieb: die Rentenversicherung folgt dann\neiner **eigenen Beitragsbemessungsgrenze** (§ 159 SGB VI — 2026: 10.400 € im Monat\nstatt 8.450 €) und einem **eigenen Beitragssatz** (§ 158 SGB VI), der sich nicht\nhälftig teilt (§ 168 Abs. 3 SGB VI).\n\n⚠️ Die **Arbeitslosenversicherung** bleibt bei der allgemeinen Grenze\n(§ 341 Abs. 4 SGB III).\n\n⚠️ Solange `sv_saetze.rv_knappschaftlich` und `…_an` nicht gepflegt sind, wird für\ndiese Person **nicht gerechnet** (Prüfketten-Befund). Ein Rückfall auf den\nallgemeinen Satz wäre für beide Seiten falsch.\n"
     },
     "verzicht_eingang_am": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Verzichtserklärung beim Arbeitgeber eingegangen am. **Nur** bei `verzicht_rv_freiheit: true`\nzulässig — ohne Erklärung muss das Feld leer bleiben (Prüfkriterien 003/004).\n"
     },
     "verzicht_gueltig_ab": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Verzicht auf die RV-Freiheit gültig ab. **Muss nach dem Eingangsdatum liegen** — der\nVerzicht wirkt nur für die Zukunft und ist für die Dauer der Beschäftigung bindend\n(Prüfkriterien 005–010).\n"
     },
     "verzicht_rv_freiheit": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Verzicht auf Rentenversicherungsfreiheit. **Dreiwertig:** `null` = nicht angegeben,\nund das ist etwas anderes als `false`.\n\n⚠️ „Das Feld darf nicht mit einer fachlichen Ausprägung vorbelegt sein.\" Ob jemand auf\nseine Versicherungsfreiheit verzichtet hat, kann die Software nicht entscheiden.\n"
     },
     "freiwilligendienst_anschluss": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Freiwilligendienst (Personengruppen 119, 120, 123): Schließt sich der Dienst\n**unmittelbar** — innerhalb von vier Wochen — an eine versicherungspflichtige\nBeschäftigung an? Historisiert an der Zeitscheibe (Migration 144).\n\nTut er das, werden die Beiträge zur **Arbeitslosenversicherung** nicht aus dem\nTaschengeld, sondern aus der **monatlichen Bezugsgröße** berechnet\n(§ 345 Nr. 4 SGB III). Bei 400 € Taschengeld und rund 3.955 € Bezugsgröße ist das\netwa das Zehnfache; die übrigen Zweige bleiben unberührt.\n\n**Dreiwertig:** `null` = nicht angegeben, `true` = schließt unmittelbar an,\n`false` = nicht.\n\n⚠️ `null` ist kein neutraler Zustand: die Prüfkette meldet dann einen **Fehler**, und\nder Monat lässt sich nicht festschreiben. Ein Vorgabewert `false` wäre die stille\nFortschreibung eines zu niedrigen Beitrags — auffallen würde er erst bei der\nBetriebsprüfung.\n"
     },
     "uebergangsbereich_anwenden": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Kennzeichen „Anwendung Übergangsbereich\" (Midijob), historisiert an der Zeitscheibe.\n**Dreiwertig:** `null` = automatisch nach dem Entgelt (Vorgabe), `true` = erzwingen,\n`false` = ausschließen.\n\n⚠️ Der Übergangsbereich gilt von Gesetzes wegen, sobald das Entgelt im Korridor liegt —\ner ist kein Wahlrecht. Die beiden ausdrücklichen Werte sind für die Fälle, die der\nAutomatismus nicht entscheiden kann (Mehrfachbeschäftigung, Bestandsfälle); jede\nAbweichung vom Korridor meldet der Lohnlauf.\n"
     },
     "rv_befreiung_antrag_am": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Tag, an dem der **Antrag auf Befreiung von der Rentenversicherungspflicht**\n(§ 6 Abs. 1b SGB VI) beim Arbeitgeber einging — nur für Minijobs (PGS 109).\n\n⚠️ Ein **Datum**, kein Häkchen: die Befreiung wirkt ab dem Beginn des Monats, in dem\nder Antrag einging, wenn der Arbeitgeber ihn der Minijob-Zentrale binnen **sechs\nWochen** meldet — sonst erst ab dem Folgemonat der Meldung.\n\nBeim Altfall (Beschäftigungsbeginn vor dem 01.01.2013, Entgelterhöhung danach über\n400 €) wird daraus die Anzeige an die Minijob-Zentrale: `POST\n/mandanten/{id}/mitarbeiter/{id}/minijob-befreiung` erzeugt die Meldungen 33/13.\n"
     },
     "rechtskreis": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "W",
       "O",
       null
      ],
      "description": "Rechtskreis des **Beschäftigungsortes** (`W` = alte Länder, `O` = Beitrittsgebiet).\n\n⚠️ `null` heißt „folgt dem Mandanten\", nicht „unbekannt\" — gepflegt wird nur der\nBeschäftigte, der woanders arbeitet als der Betrieb sitzt.\n\n⚠️ Sein Wechsel ist ein **Meldetatbestand** (Abmeldung 33 / Anmeldung 13) — aber nur\nfür Zeiträume **vor dem 01.01.2025**. Ab dann ist KENNZRK Grundstellung (DBME166);\nein Meldepaar für einen späteren Wechsel wäre ein Fehler.\n"
     },
     "betriebsstaette_id": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Der **Beschäftigungsbetrieb** (Mig. 170, Kriterien ec586c06 · 1721b032 · e0b8a69d).\n\nEin Arbeitgeber darf für mehrere Beschäftigungsbetriebe mehrere Betriebsnummern\nführen; **genau eine** ist die Hauptbetriebsnummer (HABBNR), unter der die\nBeitragsnachweise abgegeben werden. Die Meldung dieser Person trägt als Verursacher\n(**BBNRVU**) die Nummer ihres Betriebs.\n\n⚠️ `null` heißt „Hauptbetrieb\", nicht „unbekannt\" — wie beim `rechtskreis` darüber:\ngepflegt wird nur, wer in einer ANDEREN Betriebsstätte arbeitet. Die Betriebsstätten\nselbst stehen unter `/mandanten/{mandantId}/betriebsstaetten`.\n"
     },
     "uv_frei": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "ausland",
       "sgb7",
       "freistellung",
       "duales_studium",
       null
      ],
      "description": "Grund, warum in diesem Zeitraum **kein uv-pflichtiges Arbeitsentgelt** entsteht.\n`null` (Vorgabe) = uv-pflichtig — wer nichts einträgt, wird gemeldet.\n\n* `ausland` — keine UV-Pflicht wegen Auslandsbeschäftigung\n* `sgb7` — Versicherungsfreiheit in der Unfallversicherung nach SGB VII\n* `freistellung` — unwiderrufliche Freistellung von der Arbeitsleistung\n* `duales_studium` — Theoriephase eines praxisorientierten dualen Studiengangs\n\nWirkung: das UV-Entgelt des Monats ist 0, die Person steht im **zweiten Teil** der\nBeitragsabrechnung-UV statt im Lohnnachweis. Liegt der Sachverhalt **ganzjährig** vor,\nentsteht auch keine UV-Jahresmeldung.\n"
     },
     "hauptarbeitgeber": {
      "type": "boolean",
      "default": true,
      "description": "ELStAM: `true` = erstes Dienstverhältnis (die Person erhält ihre erste Steuerklasse),\n`false` = Nebenarbeitgeber (**Steuerklasse 6**).\n\n⚠️ Bis zum 09.08.2026 gab es dieses Stammdatum nicht — die Betriebsautomatik meldete\ndeshalb **jeden** Beschäftigten als Hauptarbeitgeber an. Wer es falsch stehen lässt,\nbekommt die erste Steuerklasse und behält zu wenig Lohnsteuer ein; der Fehler steckt\nin den Abzugsmerkmalen, nicht in der Rechnung.\n"
     },
     "sammelbefoerderung": {
      "type": "boolean",
      "default": false,
      "description": "Steuerfreie Sammelbeförderung zwischen Wohnung und erster Tätigkeitsstätte nach\n§ 3 Nr. 32 EStG. Wird als **Großbuchstabe F** auf der Lohnsteuerbescheinigung\nausgewiesen — fehlt er, ist die Bescheinigung falsch.\n"
     },
     "grenzgaenger_fr": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "1",
       "2",
       "3",
       null
      ],
      "description": "Französischer Grenzgänger; ergibt den **Großbuchstaben FR1/FR2/FR3**.\n⚠️ Das amtliche Muster kennt **kein nacktes `FR`** — die Ziffer ist Pflicht.\n"
     },
     "kostenstelle": {
      "type": [
       "string",
       "null"
      ],
      "maxLength": 20,
      "description": "Kostenstelle für den Buchungsstapel. ⚠️ **Wird noch nicht in die Buchungen\nübernommen** — der DATEV-Stapel bucht heute aggregiert, nicht je Person.\n"
     },
     "fremdentgelt_kv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Laufendes Entgelt aus **anderer** Beschäftigung, Zweig KV. Nur bei\nMehrfachbeschäftigung, und je Zweig getrennt — die anteilige Beitragsbemessungsgrenze\nbildet sich für jeden Versicherungszweig eigen.\n\n⚠️ Die Angabe ist **nur nötig, wenn die Person eigene RV-Beiträge leistet**. Bei\npauschalen RV-Beiträgen (Beitragsgruppe 5) nicht.\n\n⚠️ **Wird derzeit erfasst, aber noch nicht gerechnet**: die Regelmodule\n(`minijob_mindestbemessung`, `uebergangsbereich_anwendung`) sind fertig, ihre\nVerdrahtung in den Lohnlauf steht aus.\n"
     },
     "fremdentgelt_rv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "dito RV"
     },
     "fremdentgelt_av_cent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "dito AV"
     },
     "fremdentgelt_pv_cent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "dito PV"
     },
     "fremdentgelt_mehrere_ag": {
      "type": "boolean",
      "default": false,
      "description": "Es gibt **mehr als einen** weiteren Arbeitgeber. Dann sind die oben eingetragenen\nBeträge bereits vom Anwender auf die Beitragsbemessungsgrenze gekappt — bei mehreren\nArbeitgebern kann kein Programm das selbst leisten.\n"
     },
     "grundgehalt_cent": {
      "type": "integer"
     },
     "stundenlohn_cent": {
      "type": "integer"
     },
     "bav_umwandlung_cent": {
      "type": "integer",
      "description": "Monatliche Entgeltumwandlung."
     },
     "vwl_betrag_cent": {
      "type": "integer"
     }
    }
   },
   "MitarbeiterKurz": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "extern_ref": {
      "type": [
       "string",
       "null"
      ]
     },
     "vorname": {
      "type": "string"
     },
     "nachname": {
      "type": "string"
     },
     "eintritt": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "austritt": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "status": {
      "type": "string"
     }
    }
   },
   "MitarbeiterMitZeitscheiben": {
    "allOf": [
     {
      "$ref": "#/components/schemas/MitarbeiterKurz"
     },
     {
      "type": "object",
      "properties": {
       "zeitscheiben": {
        "type": "array",
        "description": "Alle Scheiben, älteste zuerst.",
        "items": {
         "type": "object"
        }
       }
      }
     }
    ]
   },
   "Fehlzeit": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "typ": {
      "type": "string",
      "enum": [
       "krankheit",
       "mutterschutz",
       "beschaeftigungsverbot",
       "unbezahlt"
      ]
     },
     "spezifikation": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "mit_entgeltfortzahlung",
       "mit_krankengeld",
       "ohne_entgeltfortzahlung_krankengeld",
       "nach_ablauf_krankengeld",
       "bei_eintritt_ohne_entgeltfortzahlung",
       null
      ],
      "description": "Nur bei `krankheit` sinnvoll. Sie entscheidet, ob Entgeltfortzahlung läuft, ob\nKrankengeld gezahlt wird und ob eine EEL-Bescheinigung fällig wird.\n"
     },
     "au": {
      "type": "boolean",
      "description": "Arbeitsunfähigkeit ärztlich bescheinigt."
     },
     "von": {
      "type": "string",
      "format": "date"
     },
     "bis": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Leer = noch offen."
     },
     "anmerkung": {
      "type": [
       "string",
       "null"
      ]
     },
     "mutmasslicher_entbindungstag": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Mutterschutz/Beschäftigungsverbot — ärztlich bescheinigter voraussichtlicher Entbindungstag (Pflicht für den U2-Antrag, DSER MUTEN)."
     },
     "bescheinigte_stunden": {
      "type": [
       "number",
       "null"
      ],
      "description": "**ANZAHL-STD** der Entgeltbescheinigung (§ 107 SGB IV), manuell erfasst — Dezimalstunden.\n\nPflichtenheft S. 216 · Kriterium 176001e9 (F1): „Die Anzahl der Stunden wird maschinell\naus den tatsächlich abgerechneten Stunden (inkl. Stunden der Mehrarbeit) ermittelt.\nSofern diese Werte im Programmsystem nicht vorhanden sind, ist die Anzahl der Stunden\nmanuell zu erfassen.\"\n\n⚠️ `null` heißt **maschinell ermitteln** (Ist-Stunden, sonst die vertragliche\nArbeitszeit), nicht „null Stunden\" — eine 0 weist die amtliche Prüfung mit `DBZA020`\nzurück.\n"
     },
     "entbindungstag": {
      "type": [
       "string",
       "null"
      ],
      "format": "date",
      "description": "Tatsächlicher Entbindungstag. Das Nachtragen löst **keine** Stornierung des Antrags aus."
     },
     "art_beschaeftigungsverhaeltnis": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Beschäftigungsverbot — Art des Beschäftigungsverhältnisses nach der DSER-Datensatzbeschreibung (DBBT ARTBV, zulässig 0–3), Anwendereingabe ohne Vorbelegung."
     },
     "erstellt_am": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "WebhookHuelle": {
    "type": "object",
    "description": "Die Hülle jeder Zustellung. Der Rumpf des Ereignisses steht in `daten`; die Signatur\nkommt im Kopf `x-lohnfluss-signatur` (HMAC-SHA256 über den rohen Rumpf), die Art des\nEreignisses zusätzlich in `x-lohnfluss-event`.\n",
    "properties": {
     "event": {
      "type": "string",
      "example": "lohnlauf.festgeschrieben"
     },
     "mandant_id": {
      "type": "integer"
     },
     "zeit": {
      "type": "string",
      "format": "date-time",
      "description": "Zeitpunkt der Einreihung (ISO 8601)."
     },
     "daten": {
      "type": "object",
      "description": "Ereignisabhängiger Rumpf, z. B. `{ lauf_id, monat, summen, warnungen }`."
     }
    }
   },
   "Befund": {
    "type": "object",
    "description": "Ein Ergebnis der Prüfkette für eine Person in einem Monat.\n\n⚠️ **`stufe` ist die wichtigste Angabe.** `fehler` heißt „so darf keine Meldung\nentstehen\" — das Festschreiben ist gesperrt, bis er behoben ist. `warnung` heißt „es\nrechnet, aber jemand sollte hinsehen\" und hält nicht auf. Wer beides gleich behandelt,\nmacht die Unterscheidung wertlos.\n",
    "properties": {
     "mitarbeiter_id": {
      "type": "integer"
     },
     "name": {
      "type": "string",
      "example": "Musterfrau, Erika"
     },
     "stufe": {
      "type": "string",
      "enum": [
       "fehler",
       "warnung"
      ]
     },
     "quelle": {
      "type": "string",
      "description": "Welche Regel angeschlagen hat, z. B. `personalstamm`, `umlagekasse`, `lauf`."
     },
     "meldung": {
      "type": "string"
     }
    }
   },
   "Bewegungszeile": {
    "type": "object",
    "description": "Eine Zeile Bewegungsdaten. Welche Felder zählen, hängt an `art`.",
    "properties": {
     "art": {
      "type": "string",
      "description": "Art der Bewegung, z. B. `stunden`, `zuschlag_nacht`, `einmalzahlung`. Kurzarbeit (seit 09.08.2026 erfassbar, Rechnung folgt): `mehrarbeit`, `kug_ausfall`, `kug_zuschuss`, `kug_hinzuverdienst`, `kug_nicht_wirtschaftlich`. Eine unbekannte Art wird mit 422 abgewiesen; Arten ohne Wirkung liefern einen Hinweis in der Antwort."
     },
     "menge": {
      "type": [
       "number",
       "null"
      ],
      "description": "Stunden oder Tage."
     },
     "prozent": {
      "type": [
       "number",
       "null"
      ],
      "description": "Zuschlagssatz."
     },
     "betrag_cent": {
      "type": [
       "integer",
       "null"
      ]
     },
     "von": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "bis": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "quelle_ref": {
      "type": [
       "string",
       "null"
      ],
      "description": "Ihre Referenz — läuft unverändert durch und taucht in Prüfspuren wieder auf."
     }
    }
   },
   "LaufErgebnis": {
    "type": "object",
    "properties": {
     "lauf_id": {
      "type": "integer"
     },
     "monat": {
      "type": "string"
     },
     "status": {
      "type": "string"
     },
     "summen": {
      "type": "object",
      "description": "Betriebssummen des Laufs, alle Beträge in Cent."
     },
     "warnungen": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Auffälligkeiten, die den Lauf nicht verhindern (fehlende Stammdaten, unplausible Werte)."
     }
    }
   },
   "Dokument": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "typ": {
      "type": "string",
      "enum": [
       "payslip",
       "buchungsstapel",
       "sepa",
       "dls"
      ]
     },
     "dateiname": {
      "type": "string"
     },
     "mitarbeiter_id": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Gesetzt bei personenbezogenen Dokumenten (Abrechnung)."
     },
     "sha256": {
      "type": "string",
      "description": "Prüfsumme des Inhalts."
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "MeldungKurz": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "verfahren": {
      "type": "string"
     },
     "kennung": {
      "type": "string",
      "description": "Amtliche Datensatz-Kennung, z. B. `DSME`."
     },
     "datensatz_format": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "example": "entwurf"
     }
    }
   },
   "Meldung": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "verfahren": {
      "type": "string",
      "enum": [
       "deuev",
       "beitragsnachweis",
       "aag",
       "dsvv",
       "eel",
       "eau",
       "a1",
       "elstam",
       "elster_lsta",
       "elster_lstb"
      ]
     },
     "richtung": {
      "type": "string",
      "enum": [
       "ausgehend",
       "eingehend"
      ]
     },
     "datensatz_format": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "entwurf",
       "geprueft",
       "gesendet",
       "bestaetigt",
       "fehler",
       "ersetzt",
       "abgelehnt",
       "zurueckgenommen"
      ],
      "description": "`abgelehnt` und `zurueckgenommen` kommen aus den eingehenden A1-Rückmeldungen (Migration 112). `abgelehnt` ist ausdrücklich NICHT `fehler`: die Übermittlung war einwandfrei, es ist eine Sachentscheidung des Trägers. `zurueckgenommen` heißt, eine bereits erteilte Bescheinigung wurde storniert — die Person führt womöglich noch ein PDF mit, das nicht mehr gilt.\n"
     },
     "kernpruefung_ok": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Ergebnis der amtlichen GKV-Kernprüfung."
     },
     "mitarbeiter_id": {
      "type": [
       "integer",
       "null"
      ]
     },
     "gesendet_am": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "PosteingangEintrag": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer"
     },
     "kategorie": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "neu",
       "gelesen",
       "erledigt"
      ]
     },
     "betreff": {
      "type": "string"
     },
     "eingang_am": {
      "type": "string",
      "format": "date-time"
     }
    }
   }
  }
 },
 "webhooks": {
  "lohnlauf.probe_fertig": {
   "post": {
    "summary": "Probelauf gerechnet",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/WebhookHuelle"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Empfang bestätigt."
     }
    }
   }
  },
  "lohnlauf.festgeschrieben": {
   "post": {
    "summary": "Lauf festgeschrieben",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/WebhookHuelle"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Empfang bestätigt."
     }
    }
   }
  },
  "dokumente.bereit": {
   "post": {
    "summary": "Dokumente eines Laufs erzeugt",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/WebhookHuelle"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Empfang bestätigt."
     }
    }
   }
  }
 },
 "x-webhook-transport": {
  "beschreibung": "Jede Zustellung ist ein POST mit zwei Kopfzeilen: `x-lohnfluss-event` nennt das Ereignis,\n`x-lohnfluss-signatur` trägt einen HMAC-SHA256 über den **rohen** Body, gebildet mit Ihrem\nWebhook-Secret. Prüfen Sie die Signatur, bevor Sie den Body auswerten.\nFehlgeschlagene Zustellungen werden mit wachsendem Abstand erneut versucht.\n",
  "header": {
   "x-lohnfluss-event": "Name des Ereignisses.",
   "x-lohnfluss-signatur": "HMAC-SHA256 (hex) über den Rohbody."
  }
 }
}
