{
  "openapi": "3.1.0",
  "info": {
    "title": "Bodo API",
    "version": "2026-11-01",
    "description": "Die öffentliche REST-API von Bodo: dieselben Funktionen wie Web und MCP, mit denselben Rechten.\n\nVersion über den Header `Bodo-Version: YYYY-MM-DD` (Pin je Schlüssel, der Request überschreibt). Bewegliche Operationen nur mit `Bodo-Preview: true`.\n\nFehler kommen als `application/problem+json` (RFC 9457) mit stabilem `code`. Neue Felder, neue Codes und neue Aufzählungswerte sind additiv — Clients lesen tolerant."
  },
  "servers": [
    {
      "url": "https://api.bodo-app.com/v1",
      "description": "Produktion"
    },
    {
      "url": "https://rc-api.bodo-app.com/v1",
      "description": "Release-Kandidat (RC) — derselbe Vertrag vor der Auslieferung."
    }
  ],
  "security": [
    {
      "bearer": []
    },
    {
      "oauth2": []
    }
  ],
  "tags": [
    {
      "name": "meta",
      "description": "Selbstauskunft des Prinzipals, Limit-Stand und die Spec selbst."
    },
    {
      "name": "contacts",
      "description": "Kontakte (Personen) — dieselbe Menge wie die Kontaktliste im Web."
    },
    {
      "name": "companies",
      "description": "Firmen (Organisationen) — dieselbe Menge wie die Kontaktliste im Web."
    },
    {
      "name": "tasks",
      "description": "Aufgaben — lesen, anlegen, ändern, löschen und erledigen."
    },
    {
      "name": "documents",
      "description": "Dokumente — lesen, Datei herunterladen, aus einem Upload anlegen (lange Operation), umbenennen und löschen."
    },
    {
      "name": "uploads",
      "description": "Upload-Sitzungen — ein Hochlade-Ziel (Methode, URL, Header) für eine Datei, aus der dann ein Dokument entsteht."
    },
    {
      "name": "batch",
      "description": "Batch — bis zu 20 unabhängige Aufrufe in einer Anfrage, jeder mit eigener Antwort."
    },
    {
      "name": "operations",
      "description": "Lange Läufe — Status, Fortschritt, Ergebnis oder Fehler einer 202-Antwort."
    },
    {
      "name": "webhook_endpoints",
      "description": "Webhook-Endpunkte — abonnieren, ändern, Secret drehen, testen, löschen und das Zustell-Log lesen."
    },
    {
      "name": "events",
      "description": "Ereignisse — dünne Hinweise auf geänderte Objekte, 30 Tage, gefiltert nach Leserecht."
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "operationId": "me.get",
        "summary": "Wer bin ich?",
        "description": "Prinzipal, Organisation, Schlüssel (ohne Geheimnis) und die wirksamen Scopes. Der erste Aufruf jedes Clients.",
        "tags": [
          "meta"
        ],
        "x-bodo-cost": {
          "class": "meta",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Die Selbstauskunft.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/rate_limit": {
      "get": {
        "operationId": "rateLimit.get",
        "summary": "Stand der Limits",
        "description": "Kontingent, Rest und Rücksetzzeit je geltender Politik, ohne selbst nennenswert zu kosten. Solange `metered` false ist, nennt die Antwort die deklarierten Politiken, gezählt wird noch nicht: `remaining` steht dann auf dem vollen Kontingent und `resetSeconds` auf 0.",
        "tags": [
          "meta"
        ],
        "x-bodo-cost": {
          "class": "meta",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Der Limit-Stand.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitStatus"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "openapi.get",
        "summary": "Die OpenAPI-Spec",
        "description": "Die eingefrorene Spec einer Version; ohne `version` die aufgelöste Version des Requests.",
        "tags": [
          "meta"
        ],
        "x-bodo-cost": {
          "class": "meta",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": null,
        "parameters": [
          {
            "name": "version",
            "in": "query",
            "description": "Version `YYYY-MM-DD`, deren Spec geliefert wird.",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Das OpenAPI-3.1-Dokument.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenApiDocument"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/contacts": {
      "get": {
        "operationId": "contacts.list",
        "summary": "Kontakte auflisten",
        "description": "Seite der Kontakte, neueste Änderung zuerst. Mit `q` Volltextsuche (Relevanz), mit `updatedSince` Abgleich, mit `includeDeleted=true` samt Löschmarkern.",
        "tags": [
          "contacts"
        ],
        "x-bodo-cost": {
          "class": "list",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "contacts:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Ressource, Filter und Sortierung gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "includeDeleted",
            "in": "query",
            "description": "`true` liefert Löschmarker `{ object, id, deleted: true, deletedAt }` (ohne Inhalt). Nur zusammen mit `updatedSince`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`-updatedAt` (neueste Änderung zuerst, Standard) oder `updatedAt`.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "-updatedAt",
                "updatedAt"
              ],
              "x-closed-enum": true
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Kontakte.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "post": {
        "operationId": "contacts.create",
        "summary": "Kontakt anlegen",
        "description": "Legt einen Kontakt an. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "contacts"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "contacts:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Felder des neuen Kontakt-Objekts; unbekannte Felder antworten 422.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Kontakt angelegt.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/contacts/count": {
      "get": {
        "operationId": "contacts.count",
        "summary": "Kontakte zählen",
        "description": "Anzahl der sichtbaren Kontakte mit denselben Filtern wie die Liste; gedeckelt (`capped`).",
        "tags": [
          "contacts"
        ],
        "x-bodo-cost": {
          "class": "count",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "contacts:read",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Die Anzahl.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/contacts/{id}": {
      "get": {
        "operationId": "contacts.get",
        "summary": "Kontakt lesen",
        "description": "Kontakt mit allen öffentlichen Feldern. Unbekannt, fremd und unsichtbar antworten gleich: 404.",
        "tags": [
          "contacts"
        ],
        "x-bodo-cost": {
          "class": "get",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "contacts:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`con_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^con_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakt.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "patch": {
        "operationId": "contacts.update",
        "summary": "Kontakt ändern",
        "description": "JSON Merge Patch (RFC 7396): nur gesendete Felder ändern sich; `null` leert nur, wo das Feld leerbar ist (sonst 422). Preview-Kanal.",
        "tags": [
          "contacts"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "contacts:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`con_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^con_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "requestBody": {
          "description": "Die zu ändernden Felder.",
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/ContactUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kontakt geändert.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "delete": {
        "operationId": "contacts.delete",
        "summary": "Kontakt löschen",
        "description": "Löscht einen Kontakt (Papierkorb). Familie `loeschen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "contacts"
        ],
        "x-bodo-cost": {
          "class": "delete",
          "points": 10
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "contacts:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`con_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^con_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "responses": {
          "204": {
            "description": "Kontakt gelöscht.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/companies": {
      "get": {
        "operationId": "companies.list",
        "summary": "Firmen auflisten",
        "description": "Seite der Firmen, neueste Änderung zuerst. Mit `q` Volltextsuche (Relevanz), mit `updatedSince` Abgleich, mit `includeDeleted=true` samt Löschmarkern.",
        "tags": [
          "companies"
        ],
        "x-bodo-cost": {
          "class": "list",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "companies:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Ressource, Filter und Sortierung gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "includeDeleted",
            "in": "query",
            "description": "`true` liefert Löschmarker `{ object, id, deleted: true, deletedAt }` (ohne Inhalt). Nur zusammen mit `updatedSince`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`-updatedAt` (neueste Änderung zuerst, Standard) oder `updatedAt`.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "-updatedAt",
                "updatedAt"
              ],
              "x-closed-enum": true
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Firmen.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "post": {
        "operationId": "companies.create",
        "summary": "Firma anlegen",
        "description": "Legt eine Firma an. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "companies"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "companies:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Felder des neuen Firma-Objekts; unbekannte Felder antworten 422.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Firma angelegt.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/companies/count": {
      "get": {
        "operationId": "companies.count",
        "summary": "Firmen zählen",
        "description": "Anzahl der sichtbaren Firmen mit denselben Filtern wie die Liste; gedeckelt (`capped`).",
        "tags": [
          "companies"
        ],
        "x-bodo-cost": {
          "class": "count",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "companies:read",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Die Anzahl.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/companies/{id}": {
      "get": {
        "operationId": "companies.get",
        "summary": "Firma lesen",
        "description": "Firma mit allen öffentlichen Feldern. Unbekannt, fremd und unsichtbar antworten gleich: 404.",
        "tags": [
          "companies"
        ],
        "x-bodo-cost": {
          "class": "get",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "companies:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`cmp_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^cmp_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Firma.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "patch": {
        "operationId": "companies.update",
        "summary": "Firma ändern",
        "description": "JSON Merge Patch (RFC 7396): nur gesendete Felder ändern sich; `null` leert nur, wo das Feld leerbar ist (sonst 422). Preview-Kanal.",
        "tags": [
          "companies"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "companies:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`cmp_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^cmp_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "requestBody": {
          "description": "Die zu ändernden Felder.",
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Firma geändert.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "delete": {
        "operationId": "companies.delete",
        "summary": "Firma löschen",
        "description": "Löscht eine Firma (Papierkorb). Familie `loeschen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "companies"
        ],
        "x-bodo-cost": {
          "class": "delete",
          "points": 10
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "companies:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`cmp_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^cmp_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "responses": {
          "204": {
            "description": "Firma gelöscht.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/tasks": {
      "get": {
        "operationId": "tasks.list",
        "summary": "Aufgaben auflisten",
        "description": "Seite der Aufgaben, neueste Änderung zuerst. Mit `q` Volltextsuche (Relevanz), mit `updatedSince` Abgleich, mit `includeDeleted=true` samt Löschmarkern.",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "list",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "tasks:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Ressource, Filter und Sortierung gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "includeDeleted",
            "in": "query",
            "description": "`true` liefert Löschmarker `{ object, id, deleted: true, deletedAt }` (ohne Inhalt). Nur zusammen mit `updatedSince`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`-updatedAt` (neueste Änderung zuerst, Standard) oder `updatedAt`.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "-updatedAt",
                "updatedAt"
              ],
              "x-closed-enum": true
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Aufgaben.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "post": {
        "operationId": "tasks.create",
        "summary": "Aufgabe anlegen",
        "description": "Legt eine Aufgabe an. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "tasks:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Felder des neuen Aufgabe-Objekts; unbekannte Felder antworten 422.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaskCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Aufgabe angelegt.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/tasks/count": {
      "get": {
        "operationId": "tasks.count",
        "summary": "Aufgaben zählen",
        "description": "Anzahl der sichtbaren Aufgaben mit denselben Filtern wie die Liste; gedeckelt (`capped`).",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "count",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "tasks:read",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Die Anzahl.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/tasks/{id}": {
      "get": {
        "operationId": "tasks.get",
        "summary": "Aufgabe lesen",
        "description": "Aufgabe mit allen öffentlichen Feldern. Unbekannt, fremd und unsichtbar antworten gleich: 404.",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "get",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "tasks:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`tsk_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^tsk_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Aufgabe.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "patch": {
        "operationId": "tasks.update",
        "summary": "Aufgabe ändern",
        "description": "JSON Merge Patch (RFC 7396): nur gesendete Felder ändern sich; `null` leert nur, wo das Feld leerbar ist (sonst 422). Preview-Kanal.",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "tasks:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`tsk_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^tsk_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "requestBody": {
          "description": "Die zu ändernden Felder.",
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/TaskUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Aufgabe geändert.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "delete": {
        "operationId": "tasks.delete",
        "summary": "Aufgabe löschen",
        "description": "Löscht eine Aufgabe (Papierkorb). Familie `loeschen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "delete",
          "points": 10
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "tasks:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`tsk_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^tsk_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "responses": {
          "204": {
            "description": "Aufgabe gelöscht.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/tasks/{id}/complete": {
      "post": {
        "operationId": "tasks.complete",
        "summary": "Aufgabe erledigen",
        "description": "Setzt eine Aufgabe auf den Erledigt-Status ihres Ablaufs. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "tasks"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "tasks:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`tsk_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^tsk_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "responses": {
          "200": {
            "description": "Aufgabe erledigt.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/documents": {
      "get": {
        "operationId": "documents.list",
        "summary": "Dokumente auflisten",
        "description": "Seite der Dokumente, neueste Änderung zuerst. Mit `q` Volltextsuche (Relevanz), mit `updatedSince` Abgleich, mit `includeDeleted=true` samt Löschmarkern.",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "list",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "documents:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Ressource, Filter und Sortierung gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "includeDeleted",
            "in": "query",
            "description": "`true` liefert Löschmarker `{ object, id, deleted: true, deletedAt }` (ohne Inhalt). Nur zusammen mit `updatedSince`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`-updatedAt` (neueste Änderung zuerst, Standard) oder `updatedAt`.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "-updatedAt",
                "updatedAt"
              ],
              "x-closed-enum": true
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Dokumente.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "post": {
        "operationId": "documents.create",
        "summary": "Dokument aus einem Upload anlegen",
        "description": "Legt ein Dokument aus einer Upload-Sitzung (`POST /uploads`) an, deren Datei hochgeladen ist. Synchron geprüft: Sitzung fremd oder abgelaufen → 404, Datei fehlt → 409 `UPLOAD_INCOMPLETE`, Größe weicht ab → 422 `UPLOAD_CHECKSUM_MISMATCH`. Dann 202 mit `Location` auf die Operation: sie prüft Größe, Prüfsumme, Typ und Dateisignatur, BEVOR das Dokument entsteht, und endet mit `result.documentId` oder mit einem Problem (`UPLOAD_REJECTED`, `UPLOAD_CHECKSUM_MISMATCH`) ohne Dokument. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "long",
          "points": 10
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "documents:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Die Upload-Sitzung (`uploadId`), optional ein Name und EIN Bezug (Kontakt, Firma oder Aufgabe).",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentCreate"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Angenommen: die Operation legt ein Dokument an. `Retry-After` nennt die Sekunden bis zur ersten Abfrage.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/documents/count": {
      "get": {
        "operationId": "documents.count",
        "summary": "Dokumente zählen",
        "description": "Anzahl der sichtbaren Dokumente mit denselben Filtern wie die Liste; gedeckelt (`capped`).",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "count",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "documents:read",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Nur Einträge, die nach diesem Zeitpunkt geändert wurden (RFC 3339). Eine Löschung ist eine Änderung: mit `includeDeleted=true` erscheint sie als Marker.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Volltextsuche in der Relevanzfolge des Such-Index. Nicht zusammen mit `updatedSince`, `sort` oder `includeDeleted`.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Die Anzahl.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/documents/{id}": {
      "get": {
        "operationId": "documents.get",
        "summary": "Dokument lesen",
        "description": "Dokument mit allen öffentlichen Feldern. Unbekannt, fremd und unsichtbar antworten gleich: 404.",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "get",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "documents:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`doc_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^doc_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Dokument.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "patch": {
        "operationId": "documents.update",
        "summary": "Dokument ändern",
        "description": "JSON Merge Patch (RFC 7396): nur gesendete Felder ändern sich; `null` leert nur, wo das Feld leerbar ist (sonst 422). Preview-Kanal.",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "documents:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`doc_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^doc_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "requestBody": {
          "description": "Die zu ändernden Felder.",
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dokument geändert.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "delete": {
        "operationId": "documents.delete",
        "summary": "Dokument löschen",
        "description": "Löscht ein Dokument (Papierkorb). Familie `loeschen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "delete",
          "points": 10
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "documents:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`doc_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^doc_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          },
          {
            "$ref": "#/components/parameters/If-Match"
          }
        ],
        "responses": {
          "204": {
            "description": "Dokument gelöscht.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "412": {
            "$ref": "#/components/responses/Problem412"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/documents/{id}/content": {
      "get": {
        "operationId": "documents.content",
        "summary": "Datei herunterladen",
        "description": "Antwortet 302 mit `Location` auf eine signierte Download-URL, 5 Minuten gültig. Die URL trägt keine Zugangsdaten des Aufrufers; nach Ablauf einfach neu anfragen.",
        "tags": [
          "documents"
        ],
        "x-bodo-cost": {
          "class": "get",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "documents:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`doc_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^doc_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "302": {
            "description": "Weiterleitung auf die signierte Download-URL.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/uploads": {
      "post": {
        "operationId": "uploads.create",
        "summary": "Upload-Sitzung anlegen",
        "description": "Öffnet eine Upload-Sitzung und liefert das Hochlade-Ziel: Methode (`PUT` oder `POST`), URL und Header, 15 Minuten gültig. Danach die Rohbytes genau so senden und mit `POST /documents` und der `uploadId` das Dokument anlegen. Vor dem Anlegen prüft eine Operation Größe, SHA-256, Typ und Dateisignatur. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "uploads"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "documents:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Name, Typ, Größe und SHA-256 der Datei; unbekannte Felder antworten 422.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sitzung angelegt, mit Hochlade-Ziel.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Upload"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "502": {
            "$ref": "#/components/responses/Problem502"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/batch": {
      "post": {
        "operationId": "batch.execute",
        "summary": "Mehrere Aufrufe bündeln",
        "description": "Führt bis zu 20 Teile aus, jeden einzeln mit Scope, Preview, eigener Idempotenz, eigenen Limits und Kosten. Ein fehlschlagender Teil bricht die anderen nicht. Keine Verschachtelung; Geld-Familien sind im Batch nicht erlaubt (Teil 422 `BATCH_FAMILY_NOT_ALLOWED`). Der Umschlag kostet nichts, die Teile zählen. Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "batch"
        ],
        "x-bodo-cost": {
          "class": "batch",
          "points": 0
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Die Teile des Batches.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Je Teil eine Antwort.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/operations/{id}": {
      "get": {
        "operationId": "operations.get",
        "summary": "Operation abfragen",
        "description": "Stand einer langen Operation. Nur der Prinzipal, der sie ausgelöst hat, liest sie; jeder andere bekommt 404. `Retry-After` der 202-Antwort nennt den Abstand der ersten Abfrage.",
        "tags": [
          "operations"
        ],
        "x-bodo-cost": {
          "class": "poll",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`op_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^op_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Die Operation.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/webhook_endpoints": {
      "get": {
        "operationId": "webhookEndpoints.list",
        "summary": "Webhook-Endpunkte auflisten",
        "description": "Die Endpunkte des eigenen Prinzipals, neueste zuerst.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "list",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "webhook_endpoints:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Liste und Filter gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Endpunkte.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "post": {
        "operationId": "webhookEndpoints.create",
        "summary": "Webhook-Endpunkt anlegen",
        "description": "Legt einen Endpunkt an und liefert das Signier-Secret genau einmal. Höchstens 16 je Prinzipal (sonst 409 `WEBHOOK_ENDPOINT_LIMIT_REACHED`). Familie `konfiguration_umbauen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "webhook_endpoints:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "requestBody": {
          "description": "Name, URL und abonnierte Ereignistypen; unbekannte Felder antworten 422.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Endpunkt angelegt, mit Secret.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointWithSecret"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/webhook_endpoints/{id}": {
      "get": {
        "operationId": "webhookEndpoints.get",
        "summary": "Webhook-Endpunkt lesen",
        "description": "Ein Endpunkt des eigenen Prinzipals; fremd und unbekannt antworten gleich: 404.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "get",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "webhook_endpoints:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`we_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^we_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Der Endpunkt.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "patch": {
        "operationId": "webhookEndpoints.update",
        "summary": "Webhook-Endpunkt ändern",
        "description": "JSON Merge Patch: Name, URL, Ereignistypen; `status: active` aktiviert einen abgeschalteten Endpunkt. Familie `konfiguration_umbauen`; Preview-Kanal.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "webhook_endpoints:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`we_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^we_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "requestBody": {
          "description": "Die zu ändernden Felder.",
          "required": true,
          "content": {
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Endpunkt geändert.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "422": {
            "$ref": "#/components/responses/Problem422"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      },
      "delete": {
        "operationId": "webhookEndpoints.delete",
        "summary": "Webhook-Endpunkt löschen",
        "description": "Löscht den Endpunkt; offene Zustellungen enden. Familie `loeschen` (zählt aufs Löschbudget); Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "delete",
          "points": 10
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "webhook_endpoints:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`we_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^we_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "responses": {
          "204": {
            "description": "Endpunkt gelöscht.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/webhook_endpoints/{id}/test": {
      "post": {
        "operationId": "webhookEndpoints.sendTest",
        "summary": "Test-Ereignis senden",
        "description": "Stellt ein Ereignis `webhook.test` an diesen Endpunkt zu; es zählt nie für die Abschaltung. Familie `konfiguration_umbauen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "webhook_endpoints:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`we_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^we_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "responses": {
          "201": {
            "description": "Die angelegte Test-Zustellung.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDelivery"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/webhook_endpoints/{id}/rotate_secret": {
      "post": {
        "operationId": "webhookEndpoints.rotateSecret",
        "summary": "Signier-Secret drehen",
        "description": "Erzeugt ein neues Secret und liefert es genau einmal; das alte bleibt 24 Stunden gültig (zwei Signaturen je Zustellung). Familie `konfiguration_umbauen`; Preview-Kanal; `Idempotency-Key` ist Pflicht.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "write",
          "points": 5
        },
        "x-bodo-channel": "preview",
        "x-bodo-scope": "webhook_endpoints:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`we_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^we_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview.required"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          },
          {
            "$ref": "#/components/parameters/Idempotency-Key"
          }
        ],
        "responses": {
          "200": {
            "description": "Endpunkt mit neuem Secret.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointWithSecret"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "409": {
            "$ref": "#/components/responses/Problem409"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/webhook_endpoints/{id}/deliveries": {
      "get": {
        "operationId": "webhookEndpoints.listDeliveries",
        "summary": "Zustell-Log lesen",
        "description": "Die Zustellungen an diesen Endpunkt der letzten 30 Tage, neueste zuerst, je Ereignis mit allen Versuchen. Antwortkörper des Empfängers werden nie gespeichert.",
        "tags": [
          "webhook_endpoints"
        ],
        "x-bodo-cost": {
          "class": "list",
          "points": 2
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": "webhook_endpoints:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`we_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^we_[0-9a-z]{16,40}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Liste und Filter gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Nur Zustellungen in diesem Zustand.",
            "required": false,
            "schema": {
              "type": "string",
              "x-extensible-enum": [
                "pending",
                "in_flight",
                "delivered",
                "retry_scheduled",
                "halted",
                "exhausted",
                "dropped"
              ]
            }
          },
          {
            "name": "eventType",
            "in": "query",
            "description": "Nur Zustellungen dieses Ereignistyps.",
            "required": false,
            "schema": {
              "type": "string",
              "x-extensible-enum": [
                "contact.created",
                "contact.updated",
                "contact.deleted",
                "company.created",
                "company.updated",
                "company.deleted",
                "task.created",
                "task.updated",
                "task.completed",
                "task.deleted",
                "document.created",
                "document.deleted",
                "operation.completed",
                "webhook.test"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Zustellungen.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "events.list",
        "summary": "Ereignisse auflisten",
        "description": "Ereignisse der letzten 30 Tage, neueste zuerst, nur zu Objekten, die der Aufrufer lesen darf. Ohne Webhook-Abo der Organisation entstehen keine Ereignisse; der Abgleich läuft dann über `updatedSince`.",
        "tags": [
          "events"
        ],
        "x-bodo-cost": {
          "class": "poll",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": null,
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Einträge je Seite, 1–100; Standard 25.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaker `nextCursor` der Vorseite. An Liste und Filter gebunden, 24 h gültig (sonst 400 `CURSOR_MISMATCH`).",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Nur Ereignisse dieses Typs.",
            "required": false,
            "schema": {
              "type": "string",
              "x-extensible-enum": [
                "contact.created",
                "contact.updated",
                "contact.deleted",
                "company.created",
                "company.updated",
                "company.deleted",
                "task.created",
                "task.updated",
                "task.completed",
                "task.deleted",
                "document.created",
                "document.deleted",
                "operation.completed",
                "webhook.test"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Eine Seite Ereignisse.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    },
    "/events/{id}": {
      "get": {
        "operationId": "events.get",
        "summary": "Ereignis lesen",
        "description": "Ein Ereignis — derselbe Körper, den die Zustellung signiert, plus `object`. Ohne Leserecht auf das Objekt: 404.",
        "tags": [
          "events"
        ],
        "x-bodo-cost": {
          "class": "poll",
          "points": 1
        },
        "x-bodo-channel": "stable",
        "x-bodo-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Opake Kennung (`evt_…`). Eine Kennung anderer Art antwortet 404.",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^evt_[0-9a-z]{16,40}$"
            }
          },
          {
            "$ref": "#/components/parameters/Bodo-Version"
          },
          {
            "$ref": "#/components/parameters/Bodo-Preview"
          },
          {
            "$ref": "#/components/parameters/Accept-Language"
          }
        ],
        "responses": {
          "200": {
            "description": "Das Ereignis.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "Bodo-Version": {
                "$ref": "#/components/headers/Bodo-Version"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Event"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem400"
          },
          "401": {
            "$ref": "#/components/responses/Problem401"
          },
          "403": {
            "$ref": "#/components/responses/Problem403"
          },
          "404": {
            "$ref": "#/components/responses/Problem404"
          },
          "410": {
            "$ref": "#/components/responses/Problem410"
          },
          "429": {
            "$ref": "#/components/responses/Problem429"
          },
          "500": {
            "$ref": "#/components/responses/Problem500"
          },
          "503": {
            "$ref": "#/components/responses/Problem503"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "API-Schlüssel im `Authorization: Bearer`-Header: persönlich `bodo_uk_{live|test}_…` oder Dienstkonto `bodo_sa_{live|test}_…`.\nNie in Query oder Cookie. Die Form nie selbst per Regex prüfen."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 für Drittanbieter-Apps über den Authorization Server im Gateway: Authorization Code mit PKCE S256.\nAccess-Token 10 Minuten; Refresh-Token rotierend (jeder Refresh liefert ein neues, das alte verfällt).",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.bodo-app.com/oauth/authorize",
            "tokenUrl": "https://api.bodo-app.com/oauth/token",
            "refreshUrl": "https://api.bodo-app.com/oauth/token",
            "scopes": {
              "contacts:read": "contacts lesen",
              "contacts:write": "contacts lesen und schreiben",
              "companies:read": "companies lesen",
              "companies:write": "companies lesen und schreiben",
              "tasks:read": "tasks lesen",
              "tasks:write": "tasks lesen und schreiben",
              "documents:read": "documents lesen",
              "documents:write": "documents lesen und schreiben",
              "invoices:read": "invoices lesen",
              "invoices:write": "invoices lesen und schreiben",
              "time_entries:read": "time_entries lesen",
              "time_entries:write": "time_entries lesen und schreiben",
              "webhook_endpoints:read": "webhook_endpoints lesen",
              "webhook_endpoints:write": "webhook_endpoints lesen und schreiben"
            }
          }
        }
      }
    },
    "headers": {
      "Request-Id": {
        "description": "Kennung dieses Aufrufs (`req_…`). Steht auf JEDER Antwort, auch 401, 429 und 500, und als `requestId` im Problem-Körper.",
        "schema": {
          "type": "string"
        }
      },
      "Bodo-Version": {
        "description": "Die Version, nach der diese Antwort geformt ist (`YYYY-MM-DD`).",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit": {
        "description": "Stand der engsten Politik nach IETF-Draft, z. B. `\"key\";r=287;t=33`.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Policy": {
        "description": "Die geltenden Politiken, z. B. `\"key\";q=300;w=60, \"org\";q=3000;w=60`.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Wartezeit in Sekunden. Bei 429 und 503.",
        "schema": {
          "type": "integer"
        }
      },
      "WWW-Authenticate": {
        "description": "Das angebotene Verfahren — immer `Bearer realm=\"bodo-api\"`. Nur bei 401 (RFC 9110 § 11.5).",
        "schema": {
          "type": "string"
        }
      },
      "Content-Language": {
        "description": "Sprache von `title`, `detail` und `errors[].message` (`de` oder `en`).",
        "schema": {
          "type": "string"
        }
      },
      "Deprecation": {
        "description": "Nur bei abgekündigter Version: Zeitpunkt der Abkündigung (RFC 9745, `@<unix>`).",
        "schema": {
          "type": "string"
        }
      },
      "Sunset": {
        "description": "Nur bei abgekündigter Version: Abschaltung als HTTP-Datum (RFC 8594).",
        "schema": {
          "type": "string"
        }
      },
      "Link": {
        "description": "Nur bei abgekündigter Version: `<…/changelog/<id>>; rel=\"deprecation\"`.",
        "schema": {
          "type": "string"
        }
      },
      "ETag": {
        "description": "Revision des Objekts als starkes ETag `\"r<revision>\"`. Als `If-Match` zurückgeschickt, schreibt eine Änderung nur, wenn niemand dazwischen geändert hat.",
        "schema": {
          "type": "string"
        }
      },
      "Idempotent-Replayed": {
        "description": "`true`, wenn die Antwort das gespeicherte Ergebnis eines früheren Requests mit demselben `Idempotency-Key` wiederholt (das Objekt wird neu gelesen).",
        "schema": {
          "type": "string"
        }
      },
      "Location": {
        "description": "Bei 202 der Pfad der Operation (`/v1/operations/op_…`), bei 302 die signierte Download-URL (5 Minuten gültig).",
        "schema": {
          "type": "string"
        }
      }
    },
    "parameters": {
      "Bodo-Version": {
        "name": "Bodo-Version",
        "in": "header",
        "required": false,
        "description": "Version des Vertrags. Überschreibt den Pin des Schlüssels; ohne Header und ohne Pin gilt die aktuelle Stable.",
        "schema": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
        }
      },
      "Bodo-Preview": {
        "name": "Bodo-Preview",
        "in": "header",
        "required": false,
        "description": "`true` schaltet den Preview-Kanal für DIESEN Request. Ohne ihn antworten Preview-Operationen 404 `OPERATION_NOT_IN_VERSION`.",
        "schema": {
          "type": "string"
        }
      },
      "Accept-Language": {
        "name": "Accept-Language",
        "in": "header",
        "required": false,
        "description": "Sprache der Texte (`de`, `en`, mit q-Werten). Ohne Treffer: Deutsch.",
        "schema": {
          "type": "string"
        }
      },
      "Idempotency-Key": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Pflicht an POST und DELETE: 1–255 druckbare ASCII-Zeichen, eindeutig je beabsichtigter Änderung. Eine Wiederholung binnen 24 h liefert das gespeicherte Ergebnis; derselbe Schlüssel mit anderem Inhalt antwortet 422 `IDEMPOTENCY_PAYLOAD_MISMATCH`.",
        "schema": {
          "type": "string",
          "pattern": "^[\\x21-\\x7E]{1,255}$"
        }
      },
      "If-Match": {
        "name": "If-Match",
        "in": "header",
        "required": false,
        "description": "Optionale Vorbedingung: das zuletzt gelesene `ETag` `\"r<revision>\"`; `*` heißt ohne Vorbedingung. Eine andere Revision antwortet 412 `PRECONDITION_FAILED`, ein falsch geformter Wert 400.",
        "schema": {
          "type": "string"
        }
      },
      "Bodo-Preview.required": {
        "name": "Bodo-Preview",
        "in": "header",
        "required": true,
        "description": "Diese Operation gehört zum Preview-Kanal: `true` senden. Ohne den Header antwortet sie 404 `OPERATION_NOT_IN_VERSION`.",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "Problem400": {
        "description": "Mögliche `code`-Werte:\n- `INVALID_REQUEST` — Ungültige Anfrage\n- `BATCH_TOO_LARGE` — Batch zu groß\n- `CURSOR_MISMATCH` — Cursor passt nicht zur Anfrage\n- `UNKNOWN_PARAMETER` — Unbekannter Parameter",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem401": {
        "description": "Möglicher `code`:\n- `UNAUTHENTICATED` — Nicht authentifiziert",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          },
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WWW-Authenticate"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem403": {
        "description": "Mögliche `code`-Werte:\n- `FORBIDDEN` — Keine Berechtigung\n- `RISK_FAMILY_BLOCKED` — Risikofamilie gesperrt\n- `ORGANIZATION_MISMATCH` — Organisation passt nicht\n- `API_MODULE_DISABLED` — Öffentliche API nicht freigeschaltet",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem404": {
        "description": "Mögliche `code`-Werte:\n- `NOT_FOUND` — Nicht gefunden\n- `OPERATION_NOT_IN_VERSION` — Operation in dieser Version nicht verfügbar",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem409": {
        "description": "Mögliche `code`-Werte:\n- `IDEMPOTENCY_IN_PROGRESS` — Anfrage mit diesem Idempotency-Key läuft noch\n- `UPLOAD_INCOMPLETE` — Upload nicht abgeschlossen\n- `WEBHOOK_ENDPOINT_LIMIT_REACHED` — Zu viele Webhook-Endpunkte",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem410": {
        "description": "Möglicher `code`:\n- `VERSION_SUNSET` — API-Version abgeschaltet",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem412": {
        "description": "Möglicher `code`:\n- `PRECONDITION_FAILED` — Vorbedingung nicht erfüllt",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem422": {
        "description": "Mögliche `code`-Werte:\n- `VALIDATION_FAILED` — Validierung fehlgeschlagen\n- `IDEMPOTENCY_PAYLOAD_MISMATCH` — Idempotency-Key mit anderem Inhalt\n- `UPLOAD_CHECKSUM_MISMATCH` — Prüfsumme des Uploads stimmt nicht\n- `UPLOAD_REJECTED` — Datei abgewiesen\n- `BATCH_FAMILY_NOT_ALLOWED` — Familie im Batch nicht erlaubt\n- `WEBHOOK_URL_INVALID` — Webhook-URL ungültig",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem428": {
        "description": "Möglicher `code`:\n- `PRECONDITION_REQUIRED` — Vorbedingung erforderlich",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem429": {
        "description": "Mögliche `code`-Werte:\n- `RATE_LIMITED` — Zu viele Anfragen\n- `OVERLOADED` — Instanz ausgelastet\n- `QUOTA_EXHAUSTED` — Kontingent erschöpft",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem500": {
        "description": "Möglicher `code`:\n- `INTERNAL` — Interner Fehler",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem502": {
        "description": "Möglicher `code`:\n- `UPSTREAM` — Fehler im nachgelagerten Dienst",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem503": {
        "description": "Mögliche `code`-Werte:\n- `API_PAUSED` — API pausiert\n- `INSTANCE_PENDING` — Instanz wird aktualisiert",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/Request-Id"
          },
          "Bodo-Version": {
            "$ref": "#/components/headers/Bodo-Version"
          },
          "Content-Language": {
            "$ref": "#/components/headers/Content-Language"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "Stabile URI des Fehlertyps; endet auf `code`."
          },
          "title": {
            "type": "string",
            "description": "Konstante Kurzfassung des Fehlertyps."
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599,
            "description": "HTTP-Status dieser Antwort."
          },
          "detail": {
            "description": "Das einzelne Vorkommnis. Fehlt bei 401.",
            "type": "string"
          },
          "instance": {
            "description": "Pfad der Anfrage, die abgesagt wurde.",
            "type": "string"
          },
          "code": {
            "type": "string",
            "description": "Kurzer, stabiler Fehlercode (UPPER_SNAKE).",
            "x-extensible-enum": [
              "INVALID_REQUEST",
              "BATCH_TOO_LARGE",
              "CURSOR_MISMATCH",
              "UNKNOWN_PARAMETER",
              "UNAUTHENTICATED",
              "FORBIDDEN",
              "RISK_FAMILY_BLOCKED",
              "ORGANIZATION_MISMATCH",
              "API_MODULE_DISABLED",
              "NOT_FOUND",
              "OPERATION_NOT_IN_VERSION",
              "IDEMPOTENCY_IN_PROGRESS",
              "UPLOAD_INCOMPLETE",
              "WEBHOOK_ENDPOINT_LIMIT_REACHED",
              "VERSION_SUNSET",
              "PRECONDITION_FAILED",
              "VALIDATION_FAILED",
              "IDEMPOTENCY_PAYLOAD_MISMATCH",
              "UPLOAD_CHECKSUM_MISMATCH",
              "UPLOAD_REJECTED",
              "BATCH_FAMILY_NOT_ALLOWED",
              "WEBHOOK_URL_INVALID",
              "PRECONDITION_REQUIRED",
              "RATE_LIMITED",
              "OVERLOADED",
              "QUOTA_EXHAUSTED",
              "INTERNAL",
              "UPSTREAM",
              "API_PAUSED",
              "INSTANCE_PENDING"
            ]
          },
          "requestId": {
            "type": "string",
            "description": "Kennung dieses Aufrufs; steht auch im Header `Request-Id`."
          },
          "errors": {
            "description": "Feldfehler, nur bei Validierung.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldError"
            }
          },
          "retryAfterMs": {
            "description": "Nur bei 429/503: Wartezeit in Millisekunden — feiner als der Header `Retry-After` (ganze Sekunden), KZ#rate-limits.",
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code",
          "requestId"
        ]
      },
      "FieldError": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "description": "Pfad des Feldes in JSON-Pointer-naher Punktnotation, z. B. `email`."
          },
          "code": {
            "type": "string",
            "description": "Stabiler Feld-Code (UPPER_SNAKE); heutige Werte als `x-extensible-enum`.",
            "x-extensible-enum": [
              "INVALID_FORMAT"
            ]
          },
          "message": {
            "type": "string",
            "description": "Menschlich lesbare Erläuterung in der Antwortsprache."
          }
        },
        "required": [
          "field",
          "code",
          "message"
        ]
      },
      "Me": {
        "type": "object",
        "properties": {
          "authMethod": {
            "type": "string",
            "description": "Womit sich der Aufruf ausgewiesen hat.",
            "x-extensible-enum": [
              "apiKey",
              "oauth"
            ]
          },
          "principalType": {
            "type": "string",
            "description": "Person (`user`) oder Dienstkonto (`serviceAccount`).",
            "x-extensible-enum": [
              "user",
              "serviceAccount"
            ]
          },
          "principalId": {
            "type": "string",
            "description": "Opake Kennung des Prinzipals."
          },
          "principalName": {
            "type": "string",
            "description": "Anzeigename des Prinzipals."
          },
          "organization": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "description": "Die Organisation des Prinzipals. Sie steht nie im Pfad."
          },
          "key": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MeKey"
              },
              {
                "type": "null"
              }
            ],
            "description": "Der API-Schlüssel; `null` bei OAuth."
          },
          "grant": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MeGrant"
              },
              {
                "type": "null"
              }
            ],
            "description": "Die Zustimmung der OAuth-App; `null` beim API-Schlüssel."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Wirksame Scopes `<ressource>:<read|write>`."
          },
          "openFamilies": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Risikofamilien, die dieser Zugang öffnet (z. B. `loeschen`); leer = alle gesperrt."
          },
          "apiVersion": {
            "type": "string",
            "description": "Die aufgelöste Version dieses Requests."
          }
        },
        "required": [
          "authMethod",
          "principalType",
          "principalId",
          "principalName",
          "organization",
          "key",
          "grant",
          "scopes",
          "openFamilies",
          "apiVersion"
        ]
      },
      "MeKey": {
        "type": "object",
        "properties": {
          "kidShort": {
            "type": "string",
            "description": "Gekürzte öffentliche Kennung, z. B. `…Kx9a`. Nie das Geheimnis."
          },
          "environment": {
            "type": "string",
            "description": "`live` oder `test` (Sandbox).",
            "x-extensible-enum": [
              "live",
              "test"
            ]
          },
          "versionPin": {
            "type": "string",
            "description": "Gepinnte Version des Schlüssels (`YYYY-MM-DD`)."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
            "description": "Pflichtablauf des Schlüssels, ISO-8601 mit Zone."
          }
        },
        "required": [
          "kidShort",
          "environment",
          "versionPin",
          "expiresAt"
        ]
      },
      "MeGrant": {
        "type": "object",
        "properties": {
          "appId": {
            "type": "string",
            "pattern": "^app_[0-9A-Za-z]+$",
            "description": "Kennung der App (`client_id`, `app_…`)."
          },
          "appName": {
            "type": "string",
            "description": "Anzeigename der App, wie bei der Zustimmung gezeigt."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Scopes, denen die Person zugestimmt hat (`<ressource>:<read|write>`)."
          },
          "consentedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
            "description": "Zeitpunkt der Zustimmung, ISO-8601 mit Zone."
          },
          "consentExpiresAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
            "description": "Ablauf der Zustimmung (365 Tage), danach fragt die App erneut."
          }
        },
        "required": [
          "appId",
          "appName",
          "scopes",
          "consentedAt",
          "consentExpiresAt"
        ]
      },
      "RateLimitStatus": {
        "type": "object",
        "properties": {
          "metered": {
            "type": "boolean",
            "description": "true = `remaining` und `resetSeconds` sind gemessen; false = deklarierte Politik, noch nicht gezählt."
          },
          "policies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateLimitPolicy"
            },
            "description": "Alle geltenden Politiken, engste zuerst."
          }
        },
        "required": [
          "metered",
          "policies"
        ]
      },
      "RateLimitPolicy": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name der Politik, wie in `RateLimit-Policy`.",
            "x-extensible-enum": [
              "key",
              "write",
              "concurrency",
              "outflow",
              "org",
              "principal",
              "escalation",
              "pre_auth",
              "instance"
            ]
          },
          "quota": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Kontingent in Punkten je Fenster."
          },
          "windowSeconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991,
            "description": "Fensterlänge in Sekunden."
          },
          "remaining": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Verbleibende Punkte."
          },
          "resetSeconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Sekunden, bis wieder Punkte frei sind."
          }
        },
        "required": [
          "name",
          "quota",
          "windowSeconds",
          "remaining",
          "resetSeconds"
        ]
      },
      "OpenApiDocument": {
        "type": "object",
        "properties": {
          "openapi": {
            "type": "string",
            "description": "OpenAPI-Version, `3.1.0`."
          },
          "info": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            },
            "required": [
              "title",
              "version"
            ],
            "additionalProperties": {}
          }
        },
        "required": [
          "openapi",
          "info"
        ],
        "additionalProperties": {},
        "description": "Ein OpenAPI-3.1-Dokument."
      },
      "CountResult": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000
          },
          "capped": {
            "type": "boolean"
          }
        },
        "required": [
          "count",
          "capped"
        ]
      },
      "Contact": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "contact"
          },
          "id": {
            "type": "string",
            "pattern": "^con_[0-9a-z]{16,40}$"
          },
          "addressForm": {
            "type": "string",
            "enum": [
              "formal",
              "personal"
            ],
            "x-closed-enum": true
          },
          "birthDate": {
            "type": "string"
          },
          "companyId": {
            "type": "string",
            "pattern": "^cmp_[0-9a-z]{16,40}$"
          },
          "contactNumber": {
            "type": "string"
          },
          "countryCode": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "department": {
            "type": "string"
          },
          "dispatchPreference": {
            "type": "string",
            "x-extensible-enum": [
              "email",
              "post"
            ]
          },
          "displayName": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "gender": {
            "type": "string",
            "x-extensible-enum": [
              "male",
              "female",
              "diverse",
              "unspecified"
            ]
          },
          "isConsumer": {
            "type": "boolean"
          },
          "jobTitle": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "revision": {
            "type": "number"
          },
          "title": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "createdAt",
          "displayName",
          "revision",
          "updatedAt"
        ]
      },
      "ContactCreate": {
        "type": "object",
        "properties": {
          "addressForm": {
            "type": "string",
            "enum": [
              "formal",
              "personal"
            ],
            "x-closed-enum": true
          },
          "birthDate": {
            "type": "string"
          },
          "countryCode": {
            "type": "string"
          },
          "department": {
            "type": "string"
          },
          "dispatchPreference": {
            "type": "string",
            "x-extensible-enum": [
              "email",
              "post"
            ]
          },
          "email": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "gender": {
            "type": "string",
            "x-extensible-enum": [
              "male",
              "female",
              "diverse",
              "unspecified"
            ]
          },
          "isConsumer": {
            "type": "boolean"
          },
          "jobTitle": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "firstName",
          "lastName"
        ]
      },
      "ContactUpdate": {
        "type": "object",
        "properties": {
          "addressForm": {
            "type": "string",
            "enum": [
              "formal",
              "personal"
            ],
            "x-closed-enum": true
          },
          "birthDate": {
            "type": "string"
          },
          "countryCode": {
            "type": "string"
          },
          "department": {
            "type": "string"
          },
          "dispatchPreference": {
            "type": "string",
            "x-extensible-enum": [
              "email",
              "post"
            ]
          },
          "email": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "gender": {
            "type": "string",
            "x-extensible-enum": [
              "male",
              "female",
              "diverse",
              "unspecified"
            ]
          },
          "isConsumer": {
            "type": "boolean"
          },
          "jobTitle": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        }
      },
      "ContactDeletedMarker": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "contact"
          },
          "id": {
            "type": "string",
            "pattern": "^con_[0-9a-z]{16,40}$"
          },
          "deleted": {
            "type": "boolean",
            "const": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "deleted",
          "deletedAt"
        ]
      },
      "ContactList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/Contact"
                },
                {
                  "$ref": "#/components/schemas/ContactDeletedMarker"
                }
              ]
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      },
      "Company": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "company"
          },
          "id": {
            "type": "string",
            "pattern": "^cmp_[0-9a-z]{16,40}$"
          },
          "contactNumber": {
            "type": "string"
          },
          "countryCode": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "dispatchPreference": {
            "type": "string",
            "x-extensible-enum": [
              "email",
              "post"
            ]
          },
          "email": {
            "type": "string"
          },
          "isConsumer": {
            "type": "boolean"
          },
          "legalForm": {
            "type": "string"
          },
          "managingDirectors": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "registerNumber": {
            "type": "string"
          },
          "revision": {
            "type": "number"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "vatId": {
            "type": "string"
          },
          "website": {
            "type": "string"
          }
        },
        "required": [
          "object",
          "id",
          "createdAt",
          "name",
          "revision",
          "updatedAt"
        ]
      },
      "CompanyCreate": {
        "type": "object",
        "properties": {
          "countryCode": {
            "type": "string"
          },
          "dispatchPreference": {
            "type": "string",
            "x-extensible-enum": [
              "email",
              "post"
            ]
          },
          "email": {
            "type": "string"
          },
          "isConsumer": {
            "type": "boolean"
          },
          "legalForm": {
            "type": "string"
          },
          "managingDirectors": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "registerNumber": {
            "type": "string"
          },
          "vatId": {
            "type": "string"
          },
          "website": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ]
      },
      "CompanyUpdate": {
        "type": "object",
        "properties": {
          "countryCode": {
            "type": "string"
          },
          "dispatchPreference": {
            "type": "string",
            "x-extensible-enum": [
              "email",
              "post"
            ]
          },
          "email": {
            "type": "string"
          },
          "isConsumer": {
            "type": "boolean"
          },
          "legalForm": {
            "type": "string"
          },
          "managingDirectors": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "registerNumber": {
            "type": "string"
          },
          "vatId": {
            "type": "string"
          },
          "website": {
            "type": "string"
          }
        }
      },
      "CompanyDeletedMarker": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "company"
          },
          "id": {
            "type": "string",
            "pattern": "^cmp_[0-9a-z]{16,40}$"
          },
          "deleted": {
            "type": "boolean",
            "const": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "deleted",
          "deletedAt"
        ]
      },
      "CompanyList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/Company"
                },
                {
                  "$ref": "#/components/schemas/CompanyDeletedMarker"
                }
              ]
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      },
      "Task": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "task"
          },
          "id": {
            "type": "string",
            "pattern": "^tsk_[0-9a-z]{16,40}$"
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "description": {
            "type": "string"
          },
          "dueAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "isOpen": {
            "type": "boolean"
          },
          "priority": {
            "type": "string"
          },
          "revision": {
            "type": "number"
          },
          "startAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "status": {
            "type": "string"
          },
          "statusGroup": {
            "type": "string"
          },
          "taskNumber": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "createdAt",
          "isOpen",
          "priority",
          "revision",
          "status",
          "title",
          "updatedAt"
        ]
      },
      "TaskCreate": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "dueAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "priority": {
            "type": "string"
          },
          "startAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "title"
        ]
      },
      "TaskUpdate": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "dueAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "priority": {
            "type": "string"
          },
          "startAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
              },
              {
                "type": "null"
              }
            ]
          },
          "title": {
            "type": "string"
          }
        }
      },
      "TaskDeletedMarker": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "task"
          },
          "id": {
            "type": "string",
            "pattern": "^tsk_[0-9a-z]{16,40}$"
          },
          "deleted": {
            "type": "boolean",
            "const": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "deleted",
          "deletedAt"
        ]
      },
      "TaskList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/Task"
                },
                {
                  "$ref": "#/components/schemas/TaskDeletedMarker"
                }
              ]
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      },
      "Document": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "document"
          },
          "id": {
            "type": "string",
            "pattern": "^doc_[0-9a-z]{16,40}$"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "currentVersionNumber": {
            "type": "number"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "x-closed-enum": true
          },
          "documentTypeKey": {
            "type": "string"
          },
          "fileName": {
            "type": "string",
            "description": "Name des Dokuments ohne Dateiendung (z. B. `Angebot Musterfirma`). Die Endung des Downloads ergibt sich aus `mimeType`."
          },
          "mimeType": {
            "type": "string"
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "origin": {
            "type": "string",
            "x-extensible-enum": [
              "generated",
              "uploaded"
            ]
          },
          "revision": {
            "type": "number"
          },
          "sizeBytes": {
            "type": "number"
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "draft",
              "final"
            ]
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "createdAt",
          "fileName",
          "mimeType",
          "revision",
          "sizeBytes",
          "updatedAt"
        ]
      },
      "DocumentCreate": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "pattern": "^cmp_[0-9a-z]{16,40}$"
          },
          "contactId": {
            "type": "string",
            "pattern": "^con_[0-9a-z]{16,40}$"
          },
          "fileName": {
            "description": "Überschreibt den Namen der Upload-Sitzung; mit Dateiendung (z. B. `Angebot Musterfirma.pdf`). Gespeichert wird der Name ohne Endung, `GET` liefert ihn so zurück.",
            "type": "string"
          },
          "taskId": {
            "type": "string",
            "pattern": "^tsk_[0-9a-z]{16,40}$"
          },
          "uploadId": {
            "type": "string",
            "pattern": "^upl_[0-9a-z]{16,40}$"
          }
        },
        "required": [
          "uploadId"
        ]
      },
      "DocumentUpdate": {
        "type": "object",
        "properties": {
          "fileName": {
            "description": "Neuer Name. Eine Dateiendung wird abgeschnitten (`Angebot final.pdf` wird `Angebot final`), die Endung des Downloads ergibt sich weiter aus `mimeType`.",
            "type": "string"
          }
        }
      },
      "DocumentDeletedMarker": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "document"
          },
          "id": {
            "type": "string",
            "pattern": "^doc_[0-9a-z]{16,40}$"
          },
          "deleted": {
            "type": "boolean",
            "const": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "deleted",
          "deletedAt"
        ]
      },
      "DocumentList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/Document"
                },
                {
                  "$ref": "#/components/schemas/DocumentDeletedMarker"
                }
              ]
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      },
      "UploadCreate": {
        "type": "object",
        "properties": {
          "fileName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Dateiname mit Endung, z. B. `vertrag.pdf`. Wird der Name des Dokuments."
          },
          "contentType": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "MIME-Typ der Datei. Nur Typen der Dokument-Allowlist; jeder andere antwortet 422 `VALIDATION_FAILED`."
          },
          "sizeBytes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 52428800,
            "description": "Größe in Bytes. Muss der hochgeladenen Datei entsprechen."
          },
          "sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "SHA-256 der Datei als Hex in Kleinbuchstaben; die Operation prüft sie nach."
          }
        },
        "required": [
          "fileName",
          "contentType",
          "sizeBytes",
          "sha256"
        ]
      },
      "Upload": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "upload"
          },
          "id": {
            "type": "string",
            "pattern": "^upl_[0-9a-z]{16,40}$"
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "pending",
              "consumed",
              "expired"
            ],
            "description": "`pending` bis zum Anlegen des Dokuments, dann `consumed`; nach 24 h `expired`."
          },
          "fileName": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "sizeBytes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
            "description": "Ende der Sitzung (24 h); danach antwortet `uploadId` 404."
          },
          "upload": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "PUT",
                  "POST"
                ],
                "x-closed-enum": true,
                "description": "HTTP-Methode für die Rohbytes: `PUT` oder `POST`, je nach Speicher der Instanz. Immer die Methode aus dieser Antwort verwenden."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Ziel-URL mit eingebetteter, befristeter Berechtigung. Ohne `Authorization`-Header aufrufen."
              },
              "expiresAt": {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                "description": "Ablauf der URL (15 Minuten)."
              },
              "headers": {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string"
                },
                "description": "Header, die die Anfrage genau so senden muss (z. B. `Content-Type`). Der Rumpf sind die Rohbytes der Datei, kein Multipart; die Antwort des Speichers wird nicht ausgewertet."
              }
            },
            "required": [
              "method",
              "url",
              "expiresAt",
              "headers"
            ],
            "description": "Wohin und wie die Bytes hochgeladen werden."
          }
        },
        "required": [
          "object",
          "id",
          "status",
          "fileName",
          "contentType",
          "sizeBytes",
          "sha256",
          "createdAt",
          "expiresAt",
          "upload"
        ]
      },
      "BatchRequest": {
        "type": "object",
        "properties": {
          "requests": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchRequestPart"
            },
            "description": "1–20 Teile; ab 21 antwortet 400 `BATCH_TOO_LARGE`."
          }
        },
        "required": [
          "requests"
        ]
      },
      "BatchRequestPart": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9._-]+$",
            "description": "Eigene Kennung des Teils, eindeutig im Batch; die Antwort nennt sie wieder."
          },
          "method": {
            "type": "string",
            "enum": [
              "GET",
              "POST",
              "PATCH",
              "DELETE"
            ],
            "x-closed-enum": true
          },
          "url": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2048,
            "pattern": "^\\/[^/\\s][^\\s]*$",
            "description": "Pfad unterhalb von `/v1` samt Query, z. B. `/contacts?limit=5`."
          },
          "headers": {
            "type": "object",
            "properties": {
              "Idempotency-Key": {
                "description": "Pflicht an POST und DELETE des Teils, wie beim einzelnen Aufruf.",
                "type": "string",
                "pattern": "^[\\x21-\\x7E]{1,255}$"
              },
              "If-Match": {
                "description": "Vorbedingung des Teils.",
                "type": "string"
              }
            }
          },
          "body": {
            "description": "JSON-Körper des Teils (POST, PATCH); fehlt bei GET und DELETE.",
            "type": "object",
            "properties": {},
            "additionalProperties": {}
          }
        },
        "required": [
          "id",
          "method",
          "url"
        ]
      },
      "BatchResponse": {
        "type": "object",
        "properties": {
          "responses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchResponsePart"
            },
            "description": "Je Teil eine Antwort, in Anfrage-Reihenfolge."
          }
        },
        "required": [
          "responses"
        ]
      },
      "BatchResponsePart": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Die Kennung des Teils aus der Anfrage."
          },
          "status": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599,
            "description": "HTTP-Status des Teils."
          },
          "headers": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "string"
            },
            "description": "Header des Teils, z. B. `ETag`, `Location`, `Idempotent-Replayed`."
          },
          "body": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": {}
              },
              {
                "type": "null"
              }
            ],
            "description": "Körper des Teils — Objekt, Liste oder Problem; `null` bei 204 und 302."
          }
        },
        "required": [
          "id",
          "status",
          "headers",
          "body"
        ]
      },
      "Operation": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "operation"
          },
          "id": {
            "type": "string",
            "pattern": "^op_[0-9a-z]{16,40}$"
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "pending",
              "running",
              "succeeded",
              "failed"
            ],
            "description": "`pending` → `running` → `succeeded` oder `failed`; die letzten beiden ändern sich nicht mehr."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "progress": {
            "description": "Fortschritt in Prozent, solange die Operation läuft und ihn kennt.",
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "result": {
            "description": "Nur bei `succeeded`.",
            "$ref": "#/components/schemas/OperationResult"
          },
          "error": {
            "description": "Nur bei `failed`: der Grund als Problem.",
            "$ref": "#/components/schemas/Problem"
          }
        },
        "required": [
          "object",
          "id",
          "status",
          "createdAt",
          "updatedAt"
        ]
      },
      "OperationResult": {
        "type": "object",
        "properties": {
          "documentId": {
            "description": "Das angelegte Dokument (Upload → Dokument).",
            "type": "string",
            "pattern": "^doc_[0-9a-z]{16,40}$"
          }
        },
        "description": "Ergebnis einer erfolgreichen Operation; die Felder hängen von ihrer Art ab."
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "webhook_endpoint"
          },
          "id": {
            "type": "string",
            "pattern": "^we_[0-9a-z]{16,40}$"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string",
              "x-extensible-enum": [
                "contact.created",
                "contact.updated",
                "contact.deleted",
                "company.created",
                "company.updated",
                "company.deleted",
                "task.created",
                "task.updated",
                "task.completed",
                "task.deleted",
                "document.created",
                "document.deleted",
                "operation.completed"
              ]
            }
          },
          "owner": {
            "$ref": "#/components/schemas/WebhookEndpointOwner"
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "active",
              "disabled",
              "paused"
            ],
            "description": "`active` stellt zu; `paused` ist eine manuelle Pause (in der Web-Oberfläche oder über MCP); `disabled` hat die Zustellung abgeschaltet, der Grund steht in `disabledReason`. Ein abgeschalteter Endpunkt kommt per Änderung auf `status: active` zurück."
          },
          "disabledReason": {
            "description": "Nur bei `disabled`: `failing_72h` nach 72 h ununterbrochener Fehler, `gone_410` nach einer Antwort 410 Gone, `owner_left`, wenn die besitzende Person die Organisation verlassen hat, `grant_revoked`, wenn die OAuth-Zustimmung, über die der Endpunkt angelegt wurde, widerrufen oder abgelaufen ist.",
            "type": "string",
            "x-extensible-enum": [
              "failing_72h",
              "gone_410",
              "owner_left",
              "grant_revoked"
            ]
          },
          "disabledAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "secretHint": {
            "type": "string",
            "description": "Die letzten vier Zeichen des Signier-Secrets."
          },
          "secretRotatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "lastDelivery": {
            "$ref": "#/components/schemas/WebhookLastDelivery"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "name",
          "url",
          "eventTypes",
          "owner",
          "status",
          "secretHint",
          "createdAt",
          "updatedAt"
        ]
      },
      "WebhookEndpointWithSecret": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "webhook_endpoint"
          },
          "id": {
            "type": "string",
            "pattern": "^we_[0-9a-z]{16,40}$"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string",
              "x-extensible-enum": [
                "contact.created",
                "contact.updated",
                "contact.deleted",
                "company.created",
                "company.updated",
                "company.deleted",
                "task.created",
                "task.updated",
                "task.completed",
                "task.deleted",
                "document.created",
                "document.deleted",
                "operation.completed"
              ]
            }
          },
          "owner": {
            "$ref": "#/components/schemas/WebhookEndpointOwner"
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "active",
              "disabled",
              "paused"
            ],
            "description": "`active` stellt zu; `paused` ist eine manuelle Pause (in der Web-Oberfläche oder über MCP); `disabled` hat die Zustellung abgeschaltet, der Grund steht in `disabledReason`. Ein abgeschalteter Endpunkt kommt per Änderung auf `status: active` zurück."
          },
          "disabledReason": {
            "description": "Nur bei `disabled`: `failing_72h` nach 72 h ununterbrochener Fehler, `gone_410` nach einer Antwort 410 Gone, `owner_left`, wenn die besitzende Person die Organisation verlassen hat, `grant_revoked`, wenn die OAuth-Zustimmung, über die der Endpunkt angelegt wurde, widerrufen oder abgelaufen ist.",
            "type": "string",
            "x-extensible-enum": [
              "failing_72h",
              "gone_410",
              "owner_left",
              "grant_revoked"
            ]
          },
          "disabledAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "secretHint": {
            "type": "string",
            "description": "Die letzten vier Zeichen des Signier-Secrets."
          },
          "secretRotatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "lastDelivery": {
            "$ref": "#/components/schemas/WebhookLastDelivery"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "secret": {
            "type": "string",
            "pattern": "^whsec_[A-Za-z0-9+/]{43}=$",
            "description": "Das Signier-Secret — nur in dieser Antwort, danach nie wieder lesbar."
          }
        },
        "required": [
          "object",
          "id",
          "name",
          "url",
          "eventTypes",
          "owner",
          "status",
          "secretHint",
          "createdAt",
          "updatedAt",
          "secret"
        ]
      },
      "WebhookEndpointOwner": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "x-extensible-enum": [
              "user",
              "serviceAccount"
            ]
          },
          "id": {
            "type": "string",
            "description": "Opake Kennung des Prinzipals, wie `principalId` in `/v1/me`."
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "id",
          "name"
        ],
        "description": "Der Prinzipal, dem der Endpunkt gehört und dessen Leserecht die Zustellung filtert."
      },
      "WebhookLastDelivery": {
        "type": "object",
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "pending",
              "in_flight",
              "delivered",
              "retry_scheduled",
              "halted",
              "exhausted",
              "dropped"
            ]
          },
          "httpStatus": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          }
        },
        "required": [
          "at",
          "status"
        ],
        "description": "Die letzte Zustellung an diesen Endpunkt."
      },
      "WebhookEndpointCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048,
            "description": "https-URL des Empfängers, Port 443, ohne Zugangsdaten und Fragment, keine private oder Loopback-Adresse (sonst 422 `WEBHOOK_URL_INVALID`)."
          },
          "eventTypes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "x-extensible-enum": [
                "contact.created",
                "contact.updated",
                "contact.deleted",
                "company.created",
                "company.updated",
                "company.deleted",
                "task.created",
                "task.updated",
                "task.completed",
                "task.deleted",
                "document.created",
                "document.deleted",
                "operation.completed"
              ]
            },
            "description": "Die abonnierten Ereignistypen; nur Typen, die der Zugang lesen darf."
          }
        },
        "required": [
          "name",
          "url",
          "eventTypes"
        ]
      },
      "WebhookEndpointUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          },
          "eventTypes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "x-extensible-enum": [
                "contact.created",
                "contact.updated",
                "contact.deleted",
                "company.created",
                "company.updated",
                "company.deleted",
                "task.created",
                "task.updated",
                "task.completed",
                "task.deleted",
                "document.created",
                "document.deleted",
                "operation.completed"
              ]
            }
          },
          "status": {
            "description": "`active` aktiviert einen abgeschalteten Endpunkt und setzt die Fehlerserie zurück.",
            "type": "string",
            "enum": [
              "active"
            ],
            "x-closed-enum": true
          }
        }
      },
      "WebhookEndpointList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEndpoint"
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "webhook_delivery"
          },
          "id": {
            "type": "string",
            "pattern": "^dlv_[0-9a-z]{16,40}$"
          },
          "eventId": {
            "type": "string",
            "pattern": "^evt_[0-9a-z]{16,40}$"
          },
          "eventType": {
            "type": "string",
            "x-extensible-enum": [
              "contact.created",
              "contact.updated",
              "contact.deleted",
              "company.created",
              "company.updated",
              "company.deleted",
              "task.created",
              "task.updated",
              "task.completed",
              "task.deleted",
              "document.created",
              "document.deleted",
              "operation.completed",
              "webhook.test"
            ]
          },
          "status": {
            "type": "string",
            "x-extensible-enum": [
              "pending",
              "in_flight",
              "delivered",
              "retry_scheduled",
              "halted",
              "exhausted",
              "dropped"
            ]
          },
          "attempts": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryAttempt"
            },
            "description": "Die Versuche, ältester zuerst (höchstens 10)."
          },
          "nextAttemptAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          }
        },
        "required": [
          "object",
          "id",
          "eventId",
          "eventType",
          "status",
          "attempts",
          "createdAt"
        ]
      },
      "WebhookDeliveryAttempt": {
        "type": "object",
        "properties": {
          "attemptedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "httpStatus": {
            "description": "Fehlt ohne Antwort (Zeitüberschreitung, Verbindung).",
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          },
          "outcome": {
            "type": "string",
            "x-extensible-enum": [
              "ok",
              "http_error",
              "timeout",
              "connect_error",
              "redirect",
              "target_not_public",
              "gone"
            ]
          },
          "durationMs": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "attemptedAt",
          "outcome",
          "durationMs"
        ]
      },
      "WebhookDeliveryList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "event"
          },
          "id": {
            "type": "string",
            "pattern": "^evt_[0-9a-z]{16,40}$"
          },
          "type": {
            "type": "string",
            "x-extensible-enum": [
              "contact.created",
              "contact.updated",
              "contact.deleted",
              "company.created",
              "company.updated",
              "company.deleted",
              "task.created",
              "task.updated",
              "task.completed",
              "task.deleted",
              "document.created",
              "document.deleted",
              "operation.completed",
              "webhook.test"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
          },
          "data": {
            "$ref": "#/components/schemas/EventData"
          }
        },
        "required": [
          "object",
          "id",
          "type",
          "createdAt",
          "data"
        ]
      },
      "EventData": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "x-extensible-enum": [
              "contact",
              "company",
              "task",
              "document",
              "operation",
              "webhook_endpoint"
            ]
          },
          "id": {
            "type": "string",
            "pattern": "^[a-z]{2,3}_[0-9a-z]{16,40}$",
            "description": "Kennung des betroffenen Objekts."
          }
        },
        "required": [
          "object",
          "id"
        ],
        "description": "Welches Objekt betroffen ist — nie sein Inhalt."
      },
      "EventList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "hasMore",
          "nextCursor"
        ]
      }
    }
  }
}
