{
  "openapi": "3.0.3",
  "info": {
    "title": "DiKAS Webshop-Anbindung",
    "version": "2026-11-10",
    "description": "Aufrufe der DiKAS-Kasse, die ein eigener Webshop nutzt: Speisekarte, Online-Bestellung, Artikel und Warengruppen, Ereignis-Feed, Webhook-Ziele und Partner-Schlüssel. Beschreibung und Beispiele: https://doku.dikas.de/technik/webshop-api-referenz/",
    "contact": {
      "name": "DiKAS Support",
      "email": "support@dikas.de"
    }
  },
  "servers": [
    {
      "url": "https://{betrieb}/api/v1",
      "variables": {
        "betrieb": {
          "default": "mein-betrieb.example.de",
          "description": "Adresse der Kasse des Betriebs."
        }
      }
    }
  ],
  "tags": [
    {
      "name": "Speisekarte und Öffnungsstatus"
    },
    {
      "name": "Online-Bestellung"
    },
    {
      "name": "Artikel und Warengruppen"
    },
    {
      "name": "Ereignis-Feed"
    },
    {
      "name": "Webhook-Ziele"
    },
    {
      "name": "Partner-Schlüssel"
    }
  ],
  "paths": {
    "/online-menu/menu": {
      "get": {
        "operationId": "karte-lesen",
        "tags": [
          "Speisekarte und Öffnungsstatus"
        ],
        "summary": "Speisekarte lesen",
        "description": "Liefert die veröffentlichte Karte, gegliedert nach Warengruppen, mit Preisen, Optionen, Allergenen und Bildern. Ausgeblendete Gruppen und Artikel fehlen. Ein Artikel mit `soldOut: true` steht auf der Karte, wird beim Bestellen aber abgewiesen. Die Kasse rechnet beim Bestellen mit **ihren** Preisen: die Karte daher nicht lange zwischenspeichern.",
        "security": [],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineMenuResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SWITCH_DISABLED: Online-Bestellung ist im Betrieb ausgeschaltet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "MODULE_NOT_LICENSED: Das Modul Online-Bestellung fehlt in der Lizenz.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "keine"
      }
    },
    "/online-menu/status": {
      "get": {
        "operationId": "oeffnungsstatus-lesen",
        "tags": [
          "Speisekarte und Öffnungsstatus"
        ],
        "summary": "Öffnungsstatus lesen",
        "description": "Meldet, ob der Betrieb gerade innerhalb der Öffnungszeiten ist, und wann er schließt bzw. das nächste Mal öffnet (Öffnungszeiten und besondere Schließtage des Betriebs).",
        "security": [],
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Bestellweg: `OnlineOrder` (Vorgabe), `QrTable` oder `Reservation`. Jeder Weg fragt seinen eigenen Betriebsschalter ab."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ShopStatusResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SWITCH_DISABLED: Der angefragte Bestellweg ist im Betrieb ausgeschaltet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "keine"
      }
    },
    "/online-menu/wait-estimate": {
      "get": {
        "operationId": "wartezeit-lesen",
        "tags": [
          "Speisekarte und Öffnungsstatus"
        ],
        "summary": "Wartezeit lesen",
        "description": "Schätzt aus der Küchenlast, wann eine Abholung fertig bzw. eine Lieferung da wäre, und ob der Betrieb gerade annimmt. Die Kasse hält die Auskunft je Betrieb 30 Sekunden vor; häufiger abzufragen bringt nichts.",
        "security": [],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WaitEstimateResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SWITCH_DISABLED: Online-Bestellung ist im Betrieb ausgeschaltet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "keine"
      }
    },
    "/online-menu/shop-info": {
      "get": {
        "operationId": "shop-angaben-lesen",
        "tags": [
          "Speisekarte und Öffnungsstatus"
        ],
        "summary": "Shop-Angaben lesen",
        "description": "Öffentliche Angaben zum Shop: Name, Anschrift und Kontakt, Öffnungszeiten, angebotene Bestellwege und Zahlarten, Mindestbestellwert. Daraus lässt sich im Shop zum Beispiel ablesen, ob PayPal angeboten wird oder Sofortzahlung verlangt ist.",
        "security": [],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineShopConfigResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "keine"
      }
    },
    "/article-descriptions/{articleId}/images/{attachmentName}": {
      "get": {
        "operationId": "artikelbild-laden",
        "tags": [
          "Speisekarte und Öffnungsstatus"
        ],
        "summary": "Artikelbild laden",
        "description": "Liefert ein Bild eines Artikels als Datei. Den Dateinamen nennt die Karte in `images[].attachmentName` (bzw. `thumbnailName` für die kleine Ansicht).",
        "security": [],
        "parameters": [
          {
            "name": "articleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Artikels (`art_…`)."
          },
          {
            "name": "attachmentName",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Dateiname aus `images[].attachmentName`."
          }
        ],
        "responses": {
          "200": {
            "description": "Das Bild",
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        },
        "x-anmeldung": "keine"
      }
    },
    "/online-checkout/create": {
      "post": {
        "operationId": "online-checkout-create",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Bestellung anlegen",
        "description": "Legt eine Bestellung an und übergibt sie an die Kasse: Die Kasse prüft Öffnungszeiten, Verfügbarkeit, Optionen und Liefergebiet, rechnet mit ihren eigenen Preisen und legt einen Auftrag im Lieferservice an. Die Antwort enthält einmalig das Bestell-Geheimnis (`guestSecret`).",
        "security": [],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Neuer Wert je Bestellung (8 bis 200 Zeichen), zum Beispiel eine UUID. Wiederholt der Shop den Aufruf nach einem Netzfehler mit demselben Schlüssel und Inhalt, kommt dieselbe Bestellung zurück. Anderer Inhalt: `422 IDEMPOTENCY_KEY_REUSED`. Dringend empfohlen.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: Pflichtfeld fehlt oder ist ungültig (keine Position, Menge außerhalb 1 bis 999, Lieferadresse fehlt, ungültige E-Mail-Adresse).; SHOP_CLOSED: Außerhalb der Öffnungszeiten.; SHOP_OVERLOADED: Der Betrieb nimmt wegen Küchenlast gerade nicht an.; ARTICLE_SOLD_OUT: Ein Artikel ist heute nicht verfügbar (`soldOut`).; ARTICLE_POS_ONLY: Ein Artikel ist nur an der Kasse verkäuflich (zum Beispiel Gutscheine und Guthaben-Aufladungen).; INVALID_OPTION: Option unbekannt, mehrfach gewählt, oder in einer Einzelwahl-Gruppe mehr als eine.; REQUIRED_OPTION_MISSING: Für eine Pflichtgruppe wurde keine Option gewählt.; MIN_ORDER_AMOUNT: Mindestbestellwert nicht erreicht.; DELIVERY_AREA_NOT_COVERED: Die Lieferadresse liegt außerhalb der Liefergebiete.; DELIVERY_MODULE_REQUIRED: Lieferung braucht das Modul Lieferservice.; PREPAYMENT_REQUIRED: Der Betrieb verlangt Online-Zahlung (`stripe` oder `paypal`).; TIP_ONLINE_ONLY: Trinkgeld nur mit Online-Zahlung.; AGE_VERIFICATION_REQUIRED: Ein Artikel ist altersbeschränkt und nur vor Ort bestellbar, nicht online.; ONLINE_ORDER_DISABLED: Online-Bestellung ist im Betrieb ausgeschaltet.; ONLINEORDER_MODULE_REQUIRED: Das Modul Online-Bestellung fehlt in der Lizenz.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Ein Artikel ist unbekannt oder nicht online sichtbar.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "IDEMPOTENCY_KEY_REUSED: Derselbe `Idempotency-Key` mit anderem Inhalt (innerhalb der Wiederholungs-Zwischenspeicherung, eine Stunde).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "IDEMPOTENCY_KEY_REUSED: Der `Idempotency-Key` gehört schon zu einer anderen Bestellung (nach Ablauf dieser Stunde).; EXTERNAL_REFERENCE_CONFLICT: Dieselbe `externalReference` mit anderem Inhalt (nur mit Benutzer-Anmeldung, siehe Feld).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "keine",
        "requestBody": {
          "required": true,
          "content": {
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOnlineOrderRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOnlineOrderRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOnlineOrderRequest"
              }
            }
          }
        }
      }
    },
    "/online-checkout/{id}": {
      "get": {
        "operationId": "bestellung-lesen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Bestellung lesen",
        "description": "Liefert den aktuellen Stand einer Bestellung. Der Shop fragt damit für die Statusseite des Gastes ab (alle 10 bis 15 Sekunden genügen).",
        "security": [
          {
            "orderSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt, oder das Bestell-Geheimnis fehlt bzw. passt nicht.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bestell-Geheimnis"
      }
    },
    "/online-checkout/{id}/init-payment": {
      "post": {
        "operationId": "zahlung-starten",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Online-Zahlung starten",
        "description": "Startet die Zahlung bei Stripe oder PayPal. Stripe: die Antwort liefert `clientSecret` und `publishableKey` für Stripe.js im Browser des Gastes. PayPal: die Antwort liefert eine `redirectUrl`, zu der der Gast weitergeleitet wird. Nur für Bestellungen im Stand 1 oder 2, die noch nicht bezahlt sind.",
        "security": [
          {
            "orderSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlinePaymentInitResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt oder Geheimnis falsch.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "ALREADY_PAID: Die Bestellung ist schon bezahlt.; INVALID_STATUS: Die Bestellung ist nicht mehr im Stand 1 oder 2.; STRIPE_NOT_CONFIGURED: Der Betrieb hat Stripe nicht eingerichtet.; PAYPAL_NOT_ENABLED: PayPal ist im Shop nicht eingeschaltet.; PAYPAL_NOT_CONFIGURED: Der Betrieb hat PayPal nicht eingerichtet.; RETURN_URL_REQUIRED: PayPal braucht `returnUrl` (absolute https-Adresse).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bestell-Geheimnis",
        "requestBody": {
          "required": true,
          "content": {
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/InitOnlinePaymentRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InitOnlinePaymentRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/InitOnlinePaymentRequest"
              }
            }
          }
        }
      }
    },
    "/online-checkout/{id}/verify-payment": {
      "post": {
        "operationId": "zahlung-pruefen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Zahlung prüfen",
        "description": "Prüft die Zahlung **serverseitig bei Stripe bzw. PayPal** und markiert die Bestellung erst dann als bezahlt (`isPaid`). Der Shop ruft ihn nach der Rückkehr des Gastes auf. Eine noch nicht bezahlte Bestellung kommt unverändert zurück.",
        "security": [
          {
            "orderSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt, oder das Bestell-Geheimnis fehlt bzw. passt nicht.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bestell-Geheimnis"
      }
    },
    "/online-checkout/{id}/cancel": {
      "post": {
        "operationId": "bestellung-stornieren",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Bestellung stornieren",
        "description": "Storniert eine Bestellung, solange der Betrieb sie noch nicht angenommen hat (Stand unter 4). War sie schon online bezahlt, storniert die Kasse fiskalisch und erstattet den Betrag über den Zahlungsdienst.",
        "security": [
          {
            "orderSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt oder Geheimnis falsch.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "CANNOT_CANCEL: Der Betrieb hat die Bestellung schon angenommen; nur noch der Betrieb kann sie ablehnen.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bestell-Geheimnis"
      }
    },
    "/online-checkout/pending": {
      "get": {
        "operationId": "offene-bestellungen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Offene Bestellungen lesen",
        "description": "Die Bestellungen, die der Betrieb noch bearbeiten muss.",
        "security": [
          {
            "partnerKey": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OnlineOrderResponse"
                      },
                      "nullable": true
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-bereich": "orders:read",
        "x-anmeldung": "Partner-Schlüssel (`{bereich}`) oder Bearer"
      }
    },
    "/online-checkout/today": {
      "get": {
        "operationId": "heutige-bestellungen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Heutige Bestellungen lesen",
        "description": "Alle Online-Bestellungen des heutigen Tages, in jedem Stand. Die Antwort enthält den Namen und die Kontaktdaten des Gastes; sie sind nur im Rahmen der Bestellabwicklung zu verwenden.",
        "security": [
          {
            "partnerKey": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OnlineOrderResponse"
                      },
                      "nullable": true
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-bereich": "orders:read",
        "x-anmeldung": "Partner-Schlüssel (`{bereich}`) oder Bearer"
      }
    },
    "/online-checkout/{id}/confirm": {
      "post": {
        "operationId": "bestellung-annehmen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Bestellung annehmen",
        "description": "Nimmt eine Bestellung an: Die Kasse legt den Lieferauftrag an, erzeugt die Küchenbons und druckt sie bzw. zeigt sie auf dem Küchenmonitor, und der Gast bekommt seine Bestätigung. Ein zweiter Aufruf ändert nichts und liefert die Bestellung unverändert zurück. Zum Annehmen **nicht** den Status `4` setzen: erst `confirm` löst Bons und Auftrag aus.",
        "security": [
          {
            "partnerKey": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          },
          {
            "name": "estimatedMinutes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Zugesagte Dauer in Minuten bis zur Fertigstellung."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-bereich": "orders:manage",
        "x-anmeldung": "Partner-Schlüssel (`{bereich}`) oder Bearer"
      }
    },
    "/online-checkout/{id}/reject": {
      "post": {
        "operationId": "bestellung-ablehnen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Bestellung ablehnen",
        "description": "Lehnt eine Bestellung ab. War sie schon online bezahlt, storniert die Kasse fiskalisch und erstattet den Betrag über den Zahlungsdienst. Ein zweiter Aufruf ändert nichts.",
        "security": [
          {
            "partnerKey": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-bereich": "orders:manage",
        "x-anmeldung": "Partner-Schlüssel (`{bereich}`) oder Bearer",
        "requestBody": {
          "required": true,
          "content": {
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RejectRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RejectRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RejectRequest"
              }
            }
          }
        }
      }
    },
    "/online-checkout/{id}/status": {
      "put": {
        "operationId": "bestellstatus-setzen",
        "tags": [
          "Online-Bestellung"
        ],
        "summary": "Bestellstatus setzen",
        "description": "Setzt den Stand einer Bestellung (zum Beispiel `5` in Zubereitung, `6` bereit, `8` abgeschlossen) und benachrichtigt den Gast bei „bereit“ und „unterwegs“. Der Aufruf ändert nur den Stand: Bons und Aufträge legen `confirm` und die Kasse an. Eine feste Reihenfolge der Stände wird nicht erzwungen. Die Zuständigkeit klären Shop und Betrieb vorab: führt der Betrieb den Ablauf im Lieferservice, setzt sich der Stand dort; ein zusätzliches Setzen aus dem Shop ist dann nicht nötig.",
        "security": [
          {
            "partnerKey": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OnlineOrderResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: `status` liegt nicht zwischen 1 und 10.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Bestellung unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-bereich": "orders:manage",
        "x-anmeldung": "Partner-Schlüssel (`{bereich}`) oder Bearer",
        "requestBody": {
          "required": true,
          "content": {
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateStatusRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateStatusRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateStatusRequest"
              }
            }
          }
        }
      }
    },
    "/articles/groups": {
      "get": {
        "operationId": "warengruppen-lesen",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Warengruppen lesen",
        "description": "Liefert die Warengruppen des Betriebs, auf Wunsch nur aktive oder die Untergruppen einer Hauptgruppe.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "activeOnly",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "`true` (Vorgabe): deaktivierte Gruppen ausblenden."
          },
          {
            "name": "parentGroupId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Nur Untergruppen dieser Hauptgruppe (Gruppennummer, `100`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ArticleGroupResponse"
                      },
                      "nullable": true
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer"
      },
      "post": {
        "operationId": "warengruppe-anlegen",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Warengruppe anlegen",
        "description": "Legt eine Warengruppe an. Die übergeordnete Gruppe ergibt sich aus der Nummer: `10001` gehört zu `100`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ArticleGroupResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "DUPLICATE_GROUP_ID: Die Gruppennummer ist schon vergeben.; VALIDATION_ERROR: Name oder Gruppennummer fehlen oder sind ungültig.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer",
        "requestBody": {
          "required": true,
          "content": {
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleGroupRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleGroupRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleGroupRequest"
              }
            }
          }
        }
      }
    },
    "/articles/groups/{documentId}": {
      "patch": {
        "operationId": "warengruppe-aendern",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Warengruppe ändern",
        "description": "Ändert einzelne Felder einer Warengruppe als JSON Patch (siehe [Grundlagen](#grundlagen)). `documentId` ist die Kennung `artgrp_…`. Nicht änderbar sind unter anderem `id`, `groupId` und `parentId`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung der Warengruppe (`artgrp_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ArticleGroupResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Warengruppe unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "PATCH_TEST_FAILED: Eine `test`-Operation hat nicht gehalten: der Wert wurde inzwischen geändert; `validationErrors` nennt Pfad, erwarteten und gefundenen Wert. Es wird nichts geschrieben.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "PATCH_FIELD_UNKNOWN: Der Pfad ist unbekannt oder nicht schreibbar.; PATCH_FIELD_READONLY: Das Feld wird von der Kasse berechnet und ist nicht schreibbar.; PATCH_INVALID: Der Wert ist ungültig oder das Feld lässt sich nicht leeren.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/JsonPatchOperation"
                }
              }
            },
            "application/json-patch+json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/JsonPatchOperation"
                }
              }
            }
          }
        }
      }
    },
    "/articles": {
      "get": {
        "operationId": "artikel-lesen",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Artikel lesen",
        "description": "Liefert Artikel, auf Wunsch einer Gruppe, mit Seitenweise-Abruf. Deaktivierte Artikel fehlen in der Voreinstellung.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "groupId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Nur Artikel dieser Gruppe (Kennung `artgrp_…`)."
          },
          {
            "name": "activeOnly",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "`true` (Vorgabe): deaktivierte Artikel ausblenden."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Höchstzahl je Aufruf; ohne Angabe alle."
          },
          {
            "name": "skip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Wie viele Artikel am Anfang übersprungen werden."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ArticleResponse"
                      },
                      "nullable": true
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer"
      },
      "post": {
        "operationId": "artikel-anlegen",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Artikel anlegen",
        "description": "Legt einen Artikel an. Der Artikel erscheint in der Karte, sobald er aktiv ist, in einer Untergruppe liegt und nicht ausgeblendet ist. Optionen (Extras, Größen) und Allergene pflegt der Betrieb in der Kasse; der Shop liest sie aus der Karte.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ArticleResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: Name fehlt oder ein Wert ist ungültig.; ARTIKEL_TYP_ERFORDERLICH: Weder `taxClass` noch `taxRate` angegeben; die Kasse nimmt keinen Standardsatz an.; ARTICLE_NUMBER_TAKEN: Die Artikelnummer ist schon vergeben.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer",
        "requestBody": {
          "required": true,
          "content": {
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleRequest"
              }
            }
          }
        }
      }
    },
    "/articles/{id}": {
      "get": {
        "operationId": "artikel-lesen-einzeln",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Einen Artikel lesen",
        "description": "Liefert einen Artikel. Das Feld `version` ist die Versionsmarke, die sich bei jeder Änderung ändert.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ArticleResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Artikel unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer"
      },
      "patch": {
        "operationId": "artikel-aendern",
        "tags": [
          "Artikel und Warengruppen"
        ],
        "summary": "Artikel ändern",
        "description": "Ändert einzelne Felder eines Artikels als JSON Patch (siehe [Grundlagen](#grundlagen)): nur die genannten Felder werden geschrieben, alle anderen bleiben, auch wenn der Betrieb sie inzwischen in der Kasse geändert hat. Jede Änderung sollte eine `test`-Operation auf den Ausgangswert tragen. Ein Feld auf `null` zu setzen leert es; Name, Preis und Haken lassen sich nicht leeren. Von der Kasse berechnete Felder (`taxRate`, Zeitstempel) lassen sich nicht schreiben.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ArticleResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Artikel unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "PATCH_TEST_FAILED: Eine `test`-Operation hat nicht gehalten; es wird nichts geschrieben.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "PATCH_FIELD_UNKNOWN: Der Pfad ist unbekannt oder nicht schreibbar.; PATCH_FIELD_READONLY: Das Feld wird von der Kasse berechnet (`taxRate`, Zeitstempel).; PATCH_INVALID: Der Wert ist ungültig oder das Feld lässt sich nicht leeren.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Bearer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/JsonPatchOperation"
                }
              }
            },
            "application/json-patch+json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/JsonPatchOperation"
                }
              }
            }
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "ereignisse-lesen",
        "tags": [
          "Ereignis-Feed"
        ],
        "summary": "Ereignisse lesen",
        "description": "Liefert die Ereignisse nach einem Zeiger. Ohne `after` kommen die der letzten 24 Stunden. Die Antwort nennt in `nextCursor` den Zeiger für den nächsten Aufruf, auch wenn es nichts Neues gab. Ein Ereignis ist erst zwei Sekunden nach seiner Entstehung sichtbar.",
        "security": [
          {
            "partnerKey": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Zeiger aus `nextCursor` der letzten Antwort."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Größe der Seite, 1 bis 500; Vorgabe 100."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEventsPageResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "INVALID_CURSOR: Der Zeiger `after` ist ungültig; den Wert `nextCursor` der letzten Antwort verwenden.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-bereich": "events:read",
        "x-anmeldung": "Partner-Schlüssel (`{bereich}`) oder Bearer"
      }
    },
    "/webhook-targets": {
      "get": {
        "operationId": "webhook-ziele-lesen",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Webhook-Ziele lesen",
        "description": "Liefert alle Ziele des Betriebs, ohne Geheimnis.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookTargetResponse"
                      }
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)"
      },
      "post": {
        "operationId": "webhook-ziel-anlegen",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Webhook-Ziel anlegen",
        "description": "Legt ein Ziel an. Die Antwort enthält das Geheimnis zur Signaturprüfung **genau dieses eine Mal**.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookTargetCreatedResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "WEBHOOK_TARGET_REJECTED: Die Adresse wird abgelehnt: nicht https, nicht Port 443, nicht öffentlich auflösbar, interne oder private Adresse, oder Zugangsdaten in der Adresse. `errorMessage` nennt den Grund.; WEBHOOK_TARGET_LIMIT: Es gibt schon drei Ziele.; INVALID_NAME: Name fehlt oder ist zu lang.; INVALID_EVENT_TYPE: Eine Ereignisart ist unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookTargetRequest"
              }
            }
          }
        }
      }
    },
    "/webhook-targets/{id}": {
      "patch": {
        "operationId": "webhook-ziel-aendern",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Webhook-Ziel ändern",
        "description": "Ändert Name, Adresse, Ereignisarten oder den Schalter. Fehlende Felder bleiben unverändert. Eine neue Adresse wird wie beim Anlegen geprüft.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookTargetResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "WEBHOOK_TARGET_REJECTED: Die Adresse wird abgelehnt: nicht https, nicht Port 443, nicht öffentlich auflösbar, interne oder private Adresse, oder Zugangsdaten in der Adresse. `errorMessage` nennt den Grund.; INVALID_EVENT_TYPE: Eine Ereignisart ist unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Ziel unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookTargetRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "webhook-ziel-loeschen",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Webhook-Ziel löschen",
        "description": "Löscht ein Ziel. Noch offene Zustellungen werden als tot sichtbar; die Ereignisse bleiben im [Feed](#ereignisse-lesen).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "204": {
            "description": "Erfolg ohne Inhalt"
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Ziel unbekannt (auch bei einem zweiten Aufruf).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)"
      }
    },
    "/webhook-targets/{id}/rotate-secret": {
      "post": {
        "operationId": "webhook-geheimnis-erneuern",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Webhook-Geheimnis erneuern",
        "description": "Erzeugt ein neues Geheimnis (steht in der Antwort). Das alte gilt für die Übergangsfrist daneben weiter; in dieser Zeit stehen beide Signaturen im Kopf der Zustellung.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookTargetCreatedResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Ziel unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "INVALID_GRACE: `graceDays` liegt nicht zwischen 1 und 30.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotateWebhookSecretRequest"
              }
            }
          }
        }
      }
    },
    "/webhook-targets/deliveries": {
      "get": {
        "operationId": "webhook-zustellungen-lesen",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Zustellungen lesen",
        "description": "Zeigt die Zustellungen der Ereignisse an die Ziele: wann zuletzt versucht, mit welchem Fehler. Ohne `status` die offenen und die toten. Ein Fehlertext enthält nie den Rumpf der Gegenseite.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "`Offen`, `Erledigt` oder `Tot`."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Höchstens 500; Vorgabe 100."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDeliveryResponse"
                      }
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "INVALID_STATUS: `status` ist nicht `Offen`, `Erledigt` oder `Tot`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)"
      }
    },
    "/webhook-targets/deliveries/retry": {
      "post": {
        "operationId": "webhook-zustellungen-wiederholen",
        "tags": [
          "Webhook-Ziele"
        ],
        "summary": "Tote Zustellungen wiederholen",
        "description": "Sendet tote Zustellungen erneut, mit derselben Ereignis-Kennung. Ohne `ids` alle toten. Die Antwort nennt die Zahl der zurückgesetzten Zustellungen.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "integer",
                      "format": "int32"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RetryWebhookDeliveriesRequest"
              }
            }
          }
        }
      }
    },
    "/partner-api-keys/scopes": {
      "get": {
        "operationId": "partner-schluessel-bereiche",
        "tags": [
          "Partner-Schlüssel"
        ],
        "summary": "Bereiche lesen",
        "description": "Die zulässigen Bereiche und der Name der Kopfzeile.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PartnerApiScopesResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)"
      }
    },
    "/partner-api-keys": {
      "get": {
        "operationId": "partner-schluessel-lesen",
        "tags": [
          "Partner-Schlüssel"
        ],
        "summary": "Partner-Schlüssel lesen",
        "description": "Alle Schlüssel des Betriebs, ohne Geheimnis. `status` ist `active`, `expired` oder `revoked`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PartnerApiKeyResponse"
                      }
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)"
      },
      "post": {
        "operationId": "partner-schluessel-anlegen",
        "tags": [
          "Partner-Schlüssel"
        ],
        "summary": "Partner-Schlüssel anlegen",
        "description": "Legt einen Schlüssel an. Die Antwort enthält den vollständigen Schlüssel (`key`) **genau dieses eine Mal**. Der Schlüssel läuft nach `expiresInDays` ab (Vorgabe 365, höchstens 400); höchstens 50 gültige Schlüssel je Betrieb.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PartnerApiKeyCreatedResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "API_USER_INVALID: Der technische Benutzer existiert nicht oder ist gesperrt.; API_USER_PRIVILEGED: Der technische Benutzer ist Administrator oder Manager.; PARTNER_KEY_LIMIT: Es gibt schon 50 gültige Schlüssel.; VALIDATION_ERROR: Name, Bereich oder Gültigkeit fehlen oder sind ungültig.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "FORBIDDEN: Kein Administrator.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePartnerApiKeyRequest"
              }
            }
          }
        }
      }
    },
    "/partner-api-keys/{id}/rotate": {
      "post": {
        "operationId": "partner-schluessel-erneuern",
        "tags": [
          "Partner-Schlüssel"
        ],
        "summary": "Partner-Schlüssel erneuern",
        "description": "Erneuert den Schlüssel: gleiche Kennung, **neues Geheimnis** (steht in der Antwort). Das alte gilt noch 24 Stunden (`previousValidUntil`), damit der Shop ohne Unterbrechung umstellen kann.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PartnerApiKeyCreatedResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Schlüssel unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "PARTNER_KEY_REVOKED: Ein widerrufener Schlüssel lässt sich nicht erneuern.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotatePartnerApiKeyRequest"
              }
            }
          }
        }
      }
    },
    "/partner-api-keys/{id}": {
      "delete": {
        "operationId": "partner-schluessel-widerrufen",
        "tags": [
          "Partner-Schlüssel"
        ],
        "summary": "Partner-Schlüssel widerrufen",
        "description": "Widerruft den Schlüssel. Das wirkt mit der nächsten Anfrage; auch ein noch gültiges altes Geheimnis ist danach ungültig.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Objekts, wie sie die Kasse in früheren Antworten genannt hat (`olord_…`, `art_…`, `whz_…`, `pak_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PartnerApiKeyResponse"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ENTITY_NOT_FOUND: Schlüssel unbekannt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "errorCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "errorMessage": {
                      "type": "string",
                      "nullable": true
                    },
                    "validationErrors": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "$ref": "#/components/schemas/ValidationError"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-anmeldung": "Administrator (Bearer)"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Benutzer-Anmeldung: Token aus POST /auth/login."
      },
      "partnerKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Dikas-Api-Key",
        "description": "Partner-Schluessel (dk1_...). Der Bereich je Endpunkt steht in x-bereich."
      },
      "orderSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Order-Secret",
        "description": "Bestell-Geheimnis (guestSecret) aus der Antwort von POST /online-checkout/create."
      }
    },
    "schemas": {
      "ArticleGroupResponse": {
        "type": "object",
        "description": "Eine Warengruppe.",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Kennung (`artgrp_…`); sie gehört in `groupId` am Artikel."
          },
          "groupId": {
            "type": "string",
            "nullable": true,
            "description": "Gruppennummer: Hauptgruppe 3 Ziffern (`100`), jede Untergruppe hängt zwei Ziffern an (`10001`)."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name."
          },
          "shortName": {
            "type": "string",
            "nullable": true,
            "description": "Kurzname."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Beschreibung."
          },
          "parentId": {
            "type": "string",
            "nullable": true,
            "description": "Gruppennummer der übergeordneten Gruppe; leer bei Hauptgruppen."
          },
          "color": {
            "type": "string",
            "nullable": true,
            "description": "Farbe."
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Sortierwert."
          },
          "isActive": {
            "type": "boolean",
            "description": "Aktiv."
          },
          "version": {
            "type": "string",
            "description": "Versionsmarke der Kasse.",
            "nullable": true
          }
        }
      },
      "ArticleResponse": {
        "type": "object",
        "description": "Ein Artikel der Kasse (die für Webshops wichtigen Felder).",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Kennung (`art_…`)."
          },
          "version": {
            "type": "string",
            "description": "Versionsmarke der Kasse, ändert sich bei jeder Änderung.",
            "nullable": true
          },
          "articleNumber": {
            "type": "string",
            "nullable": true,
            "description": "Artikelnummer."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name."
          },
          "shortName": {
            "type": "string",
            "nullable": true,
            "description": "Kurzname."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Beschreibung."
          },
          "groupId": {
            "type": "string",
            "nullable": true,
            "description": "Kennung der Warengruppe (`artgrp_…`), nicht die Gruppennummer."
          },
          "price": {
            "type": "number",
            "format": "double",
            "description": "Verkaufspreis."
          },
          "taxClass": {
            "type": "integer",
            "description": "Steuerart: `0` Normalsatz, `1` ermäßigt, `99` steuerfrei.",
            "format": "int32",
            "nullable": true
          },
          "taxRate": {
            "type": "number",
            "description": "Steuersatz in Prozent; von der Kasse aus `taxClass` bestimmt und nicht schreibbar.",
            "format": "double",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "nullable": true,
            "description": "Einheit (`Stück`)."
          },
          "barcode": {
            "type": "string",
            "nullable": true,
            "description": "Strichcode."
          },
          "isActive": {
            "type": "boolean",
            "description": "`false`: weder Kasse noch Shop."
          },
          "hideFromMenu": {
            "type": "boolean",
            "description": "`true`: nicht im Shop, an der Kasse buchbar."
          },
          "manualSoldOut": {
            "type": "boolean",
            "description": "`true`: heute nicht verfügbar (der „86er“-Schalter)."
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Sortierwert."
          },
          "allergens": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true,
            "description": "Allergen-Kürzel."
          },
          "pfand": {
            "type": "number",
            "format": "double",
            "description": "Pfand je Einheit."
          }
        }
      },
      "ArticleWebImage": {
        "type": "object",
        "description": "Ein Bild eines Artikels.",
        "properties": {
          "attachmentName": {
            "type": "string",
            "nullable": true,
            "description": "Dateiname des Bildes, für [Artikelbild laden](#artikelbild-laden)."
          },
          "thumbnailName": {
            "type": "string",
            "nullable": true,
            "description": "Dateiname der kleinen Ansicht."
          },
          "caption": {
            "type": "string",
            "nullable": true,
            "description": "Bildunterschrift."
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Reihenfolge."
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Hauptbild des Artikels."
          }
        }
      },
      "CreateArticleGroupRequest": {
        "type": "object",
        "description": "Neue Warengruppe.",
        "properties": {
          "groupId": {
            "type": "string",
            "nullable": true,
            "description": "Gruppennummer, nur Ziffern: Hauptgruppe 3 Ziffern, jede Untergruppe hängt zwei Ziffern an (`100`, `10001`). Eine vorhandene Nummer ergibt `DUPLICATE_GROUP_ID`."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name."
          },
          "shortName": {
            "type": "string",
            "nullable": true,
            "description": "Kurzname."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Beschreibung."
          },
          "color": {
            "type": "string",
            "nullable": true,
            "description": "Farbe (`#C683CD`); ohne Angabe wählt die Kasse eine."
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Sortierwert."
          },
          "isActive": {
            "type": "boolean",
            "description": "Aktiv."
          }
        },
        "required": [
          "groupId",
          "name"
        ]
      },
      "CreateArticleRequest": {
        "type": "object",
        "description": "Neuer Artikel (die für Webshops wichtigen Felder).",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name des Artikels.",
            "nullable": true
          },
          "taxClass": {
            "type": "integer",
            "description": "Steuerart: `0` Normalsatz, `1` ermäßigt, `99` steuerfrei. Entweder `taxClass` oder `taxRate` ist nötig, sonst `ARTIKEL_TYP_ERFORDERLICH`.",
            "format": "int32",
            "nullable": true
          },
          "taxRate": {
            "type": "number",
            "description": "Steuersatz in Prozent; wird auf die passende Steuerart abgebildet, wenn `taxClass` fehlt. Entweder `taxClass` oder `taxRate` ist nötig.",
            "format": "double",
            "nullable": true
          },
          "groupId": {
            "type": "string",
            "description": "Kennung der Warengruppe (`artgrp_…`) — eine **Untergruppe**; Artikel ohne Gruppe oder in Hauptgruppen erscheinen nicht in der Karte. Die Kasse prüft die Kennung nicht: eine unbekannte wird angenommen, der Artikel ist dann nirgends zugeordnet.",
            "nullable": true
          },
          "price": {
            "type": "number",
            "description": "Verkaufspreis; immer angeben.",
            "format": "double"
          },
          "articleNumber": {
            "type": "string",
            "description": "Artikelnummer.",
            "nullable": true
          },
          "shortName": {
            "type": "string",
            "description": "Kurzname.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Beschreibung.",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "description": "Einheit (`Stück`).",
            "nullable": true
          },
          "barcode": {
            "type": "string",
            "description": "Strichcode.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Aktiv; sonst weder Kasse noch Shop."
          },
          "hideFromMenu": {
            "type": "boolean",
            "description": "`true`: nicht im Shop, an der Kasse buchbar."
          },
          "manualSoldOut": {
            "type": "boolean",
            "description": "`true`: heute nicht verfügbar."
          },
          "allergens": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Allergen-Kürzel.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sortierwert.",
            "format": "int32"
          },
          "pfand": {
            "type": "number",
            "format": "double",
            "description": "Pfand je Einheit."
          }
        },
        "required": [
          "name"
        ]
      },
      "CreateOnlineOrderRequest": {
        "type": "object",
        "description": "Die Bestellung eines Gastes.",
        "properties": {
          "orderType": {
            "type": "integer",
            "format": "int32",
            "description": "`0` Abholung, `1` Lieferung. (`2` ist die QR-Tischbestellung der Kasse und für Shops nicht vorgesehen.)"
          },
          "customerName": {
            "type": "string",
            "nullable": true,
            "description": "Name des Gastes, höchstens 200 Zeichen."
          },
          "customerEmail": {
            "type": "string",
            "nullable": true,
            "description": "E-Mail-Adresse des Gastes, gültig, höchstens 200 Zeichen. Die Bestätigung geht dorthin."
          },
          "customerPhone": {
            "type": "string",
            "nullable": true,
            "description": "Telefon, höchstens 30 Zeichen. Für Lieferungen sinnvoll."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineOrderItemRequest"
            },
            "nullable": true,
            "description": "Die Positionen, mindestens eine."
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true,
            "description": "`cash`, `stripe` oder `paypal`; immer angeben. Verlangt der Betrieb Sofortzahlung (`prepaymentRequired…` in [Shop-Angaben](#shop-angaben-lesen)), ist nur `stripe` oder `paypal` zulässig, sonst `PREPAYMENT_REQUIRED`."
          },
          "street": {
            "type": "string",
            "nullable": true,
            "description": "Straße, bei Lieferung Pflicht."
          },
          "houseNumber": {
            "type": "string",
            "nullable": true,
            "description": "Hausnummer (höchstens 20 Zeichen)."
          },
          "zipCode": {
            "type": "string",
            "nullable": true,
            "description": "Postleitzahl, bei Lieferung Pflicht."
          },
          "city": {
            "type": "string",
            "nullable": true,
            "description": "Ort, bei Lieferung Pflicht."
          },
          "deliveryNotes": {
            "type": "string",
            "nullable": true,
            "description": "Hinweis für den Fahrer, höchstens 2000 Zeichen."
          },
          "floor": {
            "type": "string",
            "nullable": true,
            "description": "Stockwerk."
          },
          "doorBell": {
            "type": "string",
            "nullable": true,
            "description": "Klingelschild."
          },
          "requestedTime": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wunschzeitpunkt (ISO-8601). Ohne Angabe so bald wie möglich."
          },
          "kitchenNotes": {
            "type": "string",
            "nullable": true,
            "description": "Hinweis für die Küche."
          },
          "tipAmount": {
            "type": "number",
            "format": "double",
            "description": "Trinkgeld, 0 bis 10 000; nur mit Online-Zahlung, sonst `TIP_ONLINE_ONLY`."
          },
          "externalReference": {
            "type": "string",
            "nullable": true,
            "description": "Eigene Bestellnummer des Shops, höchstens 100 Zeichen, ohne Steuerzeichen. Nur mit Benutzer-Anmeldung (Bearer) wirksam; ohne Anmeldung und mit Partner-Schlüssel wird sie ignoriert. Dieselbe Nummer mit demselben Inhalt liefert die vorhandene Bestellung zurück, mit anderem Inhalt `409 EXTERNAL_REFERENCE_CONFLICT`."
          }
        },
        "required": [
          "orderType",
          "customerName",
          "customerEmail",
          "items"
        ]
      },
      "CreatePartnerApiKeyRequest": {
        "type": "object",
        "description": "Neuer Partner-Schlüssel.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Bezeichnung, höchstens 120 Zeichen, zum Beispiel der Name des Shops."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Erlaubte Bereiche, mindestens einer (`orders:read`, `orders:manage`, `tables:read`, `events:read`)."
          },
          "apiUserId": {
            "type": "string",
            "description": "Kennung des technischen Benutzers, dessen Kassenrechte zusätzlich gelten. Kein Administrator, kein Manager."
          },
          "expiresInDays": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Gültigkeit in Tagen, 1 bis 400; ohne Angabe 365."
          }
        },
        "required": [
          "name",
          "scopes",
          "apiUserId"
        ]
      },
      "CreateWebhookTargetRequest": {
        "type": "object",
        "description": "Neues Ziel.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Bezeichnung, höchstens 120 Zeichen."
          },
          "url": {
            "type": "string",
            "description": "https-Adresse, Port 443, öffentlich erreichbar, ohne Zugangsdaten in der Adresse."
          },
          "eventTypes": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "description": "Gewünschte Ereignisarten (`order.created`, `order.status_changed`, `payment.received`, `order.cancelled`, `ticket.ready`); ohne Angabe alle."
          }
        },
        "required": [
          "name",
          "url"
        ]
      },
      "InitOnlinePaymentRequest": {
        "type": "object",
        "description": "Welcher Zahlungsdienst verwendet wird (alle Felder optional; ohne Body gilt `stripe`).",
        "properties": {
          "provider": {
            "type": "string",
            "nullable": true,
            "description": "`stripe` oder `paypal`. Ohne Angabe richtet sich der Dienst nach der Zahlart der Bestellung."
          },
          "returnUrl": {
            "type": "string",
            "nullable": true,
            "description": "PayPal: https-Adresse, auf die der Gast nach dem Bezahlen zurückkommt. Für PayPal Pflicht."
          },
          "cancelUrl": {
            "type": "string",
            "nullable": true,
            "description": "PayPal: Adresse bei Abbruch. Ohne Angabe `returnUrl`."
          }
        }
      },
      "JsonPatchOperation": {
        "type": "object",
        "description": "Eine Operation nach RFC 6902.",
        "properties": {
          "op": {
            "type": "string",
            "nullable": true,
            "description": "`replace`, `add`, `remove` oder `test`."
          },
          "path": {
            "type": "string",
            "nullable": true,
            "description": "Pfad des Feldes mit führendem Schrägstrich (`/price`)."
          },
          "value": {
            "description": "Neuer bzw. erwarteter Wert (beliebiger JSON-Wert); bei `remove` entfällt er."
          }
        },
        "required": [
          "op",
          "path"
        ]
      },
      "OnlineMenuAllergen": {
        "type": "object",
        "description": "Ein Allergen-Kürzel mit Klartext.",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true,
            "description": "Kürzel, wie es an den Artikeln steht (`A`)."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Bezeichnung (`Glutenhaltiges Getreide`)."
          }
        }
      },
      "OnlineMenuGroup": {
        "type": "object",
        "description": "Eine Warengruppe der Karte.",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Kennung der Gruppe (`artgrp_…`)."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name der Gruppe."
          },
          "color": {
            "type": "string",
            "nullable": true,
            "description": "Farbe der Gruppe (`#C683CD`), falls gepflegt."
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Sortierwert; kleinere Werte zuerst."
          },
          "parentName": {
            "type": "string",
            "nullable": true,
            "description": "Name der Hauptgruppe, zu der die Gruppe gehört."
          },
          "articles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineMenuItem"
            },
            "nullable": true,
            "description": "Die Artikel der Gruppe."
          }
        }
      },
      "OnlineMenuItem": {
        "type": "object",
        "description": "Ein Artikel der Karte.",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Kennung des Artikels (`art_…`); gehört in `items[].articleId` beim Bestellen."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Kurzbeschreibung."
          },
          "price": {
            "type": "number",
            "format": "double",
            "description": "Verkaufspreis je Einheit in der Währung des Betriebs, ohne Optionen und ohne Pfand."
          },
          "pfand": {
            "type": "number",
            "format": "double",
            "description": "Pfand je Einheit, `0` ohne Pfand. Die Kasse fügt es beim Bestellen als eigene Position hinzu; es ist nicht in `price` enthalten."
          },
          "webTitle": {
            "type": "string",
            "nullable": true,
            "description": "Abweichender Titel für den Shop, falls gepflegt."
          },
          "longDescription": {
            "type": "string",
            "nullable": true,
            "description": "Ausführliche Beschreibung."
          },
          "ingredients": {
            "type": "string",
            "nullable": true,
            "description": "Zutaten (Freitext)."
          },
          "spicyLevel": {
            "type": "integer",
            "format": "int32",
            "description": "Schärfegrad (`0` = nicht scharf)."
          },
          "isVegan": {
            "type": "boolean",
            "description": "Vegan."
          },
          "isVegetarian": {
            "type": "boolean",
            "description": "Vegetarisch."
          },
          "isGlutenFree": {
            "type": "boolean",
            "description": "Glutenfrei."
          },
          "preparationTimeMinutes": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Zubereitungsdauer in Minuten, falls gepflegt."
          },
          "soldOut": {
            "type": "boolean",
            "description": "`true`: heute nicht verfügbar. Der Artikel steht weiter auf der Karte, wird beim Bestellen aber mit `ARTICLE_SOLD_OUT` abgewiesen."
          },
          "allergens": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true,
            "description": "Allergen-Kürzel; Klartext in `allergenDefinitions`."
          },
          "additives": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true,
            "description": "Zusatzstoffe (Freitext)."
          },
          "images": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ArticleWebImage"
            },
            "nullable": true,
            "description": "Bilder des Artikels; abrufbar über [Artikelbild laden](#artikelbild-laden)."
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineMenuOptionGroup"
            },
            "nullable": true,
            "description": "Wählbare Optionen (Extras, Größen) in Gruppen."
          }
        }
      },
      "OnlineMenuOption": {
        "type": "object",
        "description": "Eine wählbare Option.",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name; er dient beim Bestellen zur Auswahl (`selectedOptions[].name`)."
          },
          "price": {
            "type": "number",
            "format": "double",
            "description": "Aufpreis. Bei `isPercent` ein Prozentsatz vom Artikelpreis (`10` = 10 %), sonst ein Geldbetrag."
          },
          "isPercent": {
            "type": "boolean",
            "description": "`true`: `price` ist ein Prozentsatz."
          },
          "isDefault": {
            "type": "boolean",
            "description": "Vorgewählt."
          },
          "appMode": {
            "type": "integer",
            "format": "int32",
            "description": "`0` normal, `1` Standard (vorgewählt), `2` im Preis enthalten (kein Aufschlag)."
          },
          "soldOut": {
            "type": "boolean",
            "description": "`true`: die Option ist heute nicht verfügbar."
          }
        }
      },
      "OnlineMenuOptionGroup": {
        "type": "object",
        "description": "Eine Gruppe wählbarer Optionen eines Artikels.",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Kennung der Gruppe."
          },
          "caption": {
            "type": "string",
            "nullable": true,
            "description": "Überschrift (`Extras`)."
          },
          "isNeeded": {
            "type": "boolean",
            "description": "`true`: mindestens eine Option muss gewählt werden, sonst `REQUIRED_OPTION_MISSING`."
          },
          "mode": {
            "type": "integer",
            "format": "int32",
            "description": "`1`: höchstens eine Option der Gruppe (Einzelwahl), sonst Mehrfachwahl."
          },
          "freeCount": {
            "type": "integer",
            "format": "int32",
            "description": "Anzahl der Optionen der Gruppe, die ohne Aufpreis enthalten sind (die günstigsten zuerst)."
          },
          "deductOnDeselect": {
            "type": "boolean",
            "description": "`true`: eine vorgewählte Option lässt sich abwählen (`ohne …`) und mindert dann den Preis."
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineMenuOption"
            },
            "nullable": true,
            "description": "Die Optionen."
          }
        }
      },
      "OnlineMenuResponse": {
        "type": "object",
        "description": "Die veröffentlichte Speisekarte des Betriebs.",
        "properties": {
          "shopName": {
            "type": "string",
            "nullable": true,
            "description": "Name des Shops."
          },
          "shopDescription": {
            "type": "string",
            "nullable": true,
            "description": "Kurzbeschreibung des Shops."
          },
          "shopSlogan": {
            "type": "string",
            "nullable": true,
            "description": "Slogan des Shops."
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineMenuGroup"
            },
            "nullable": true,
            "description": "Die Warengruppen mit ihren Artikeln. Nur Gruppen und Artikel, die online sichtbar sind."
          },
          "allergenDefinitions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineMenuAllergen"
            },
            "nullable": true,
            "description": "Klartext zu den Allergen-Kürzeln der Artikel (`allergens`)."
          }
        }
      },
      "OnlineOrderItem": {
        "type": "object",
        "description": "Eine Position einer Bestellung, wie die Kasse sie berechnet hat.",
        "properties": {
          "articleId": {
            "type": "string",
            "nullable": true,
            "description": "Kennung des Artikels."
          },
          "articleName": {
            "type": "string",
            "nullable": true,
            "description": "Name zum Zeitpunkt der Bestellung."
          },
          "quantity": {
            "type": "integer",
            "format": "int32",
            "description": "Menge."
          },
          "unitPrice": {
            "type": "number",
            "format": "double",
            "description": "Einzelpreis einschließlich der gewählten Optionen."
          },
          "totalPrice": {
            "type": "number",
            "format": "double",
            "description": "`unitPrice` mal `quantity`."
          },
          "notes": {
            "type": "string",
            "nullable": true,
            "description": "Hinweis zur Position."
          },
          "selectedOptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineOrderItemOption"
            },
            "nullable": true,
            "description": "Die gewählten Optionen mit ihrem Aufpreis."
          },
          "isAutoDeposit": {
            "type": "boolean",
            "description": "`true`: die Position ist das von der Kasse ergänzte Pfand."
          },
          "taxRate": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Steuersatz in Prozent."
          }
        }
      },
      "OnlineOrderItemOption": {
        "type": "object",
        "description": "Eine gewählte Option einer Position.",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Name der Option genau wie in der Karte (`options[].options[].name`)."
          },
          "price": {
            "type": "number",
            "format": "double",
            "description": "Aufpreis in Geld. In der Anfrage wird er nicht übernommen: die Kasse bestimmt ihn aus dem Artikel."
          },
          "inPrice": {
            "type": "boolean",
            "description": "`true`: im Preis enthalten, kein Aufschlag."
          }
        },
        "required": [
          "name"
        ]
      },
      "OnlineOrderItemRequest": {
        "type": "object",
        "description": "Eine Position der Bestellung.",
        "properties": {
          "articleId": {
            "type": "string",
            "nullable": true,
            "description": "Kennung des Artikels aus der Karte (`art_…`)."
          },
          "quantity": {
            "type": "integer",
            "format": "int32",
            "description": "Menge, 1 bis 999."
          },
          "notes": {
            "type": "string",
            "nullable": true,
            "description": "Hinweis zur Position (`ohne Zwiebeln`)."
          },
          "selectedOptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineOrderItemOption"
            },
            "nullable": true,
            "description": "Gewählte Optionen. Pflichtgruppen der Karte (`isNeeded`) müssen vertreten sein."
          }
        },
        "required": [
          "articleId",
          "quantity"
        ]
      },
      "OnlineOrderResponse": {
        "type": "object",
        "description": "Eine Online-Bestellung mit Positionen, Summen und Stand.",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Kennung der Bestellung (`olord_…`)."
          },
          "orderNumber": {
            "type": "string",
            "nullable": true,
            "description": "Bestellnummer zum Anzeigen (`ON-20261110-001`)."
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "description": "Stand: `1` eingegangen, `2` Zahlung läuft, `3` bezahlt, `4` angenommen, `5` in Zubereitung, `6` bereit, `7` unterwegs, `8` abgeschlossen, `9` storniert, `10` abgelehnt."
          },
          "orderType": {
            "type": "integer",
            "format": "int32",
            "description": "`0` Abholung, `1` Lieferung."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "description": "Angelegt (UTC)."
          },
          "changedDate": {
            "type": "string",
            "format": "date-time",
            "description": "Zuletzt geändert (UTC)."
          },
          "customerName": {
            "type": "string",
            "nullable": true,
            "description": "Name des Gastes."
          },
          "customerEmail": {
            "type": "string",
            "nullable": true,
            "description": "E-Mail des Gastes."
          },
          "customerPhone": {
            "type": "string",
            "nullable": true,
            "description": "Telefon des Gastes."
          },
          "street": {
            "type": "string",
            "nullable": true,
            "description": "Lieferadresse: Straße."
          },
          "houseNumber": {
            "type": "string",
            "nullable": true,
            "description": "Lieferadresse: Hausnummer."
          },
          "zipCode": {
            "type": "string",
            "nullable": true,
            "description": "Lieferadresse: Postleitzahl."
          },
          "city": {
            "type": "string",
            "nullable": true,
            "description": "Lieferadresse: Ort."
          },
          "deliveryNotes": {
            "type": "string",
            "nullable": true,
            "description": "Hinweis für den Fahrer."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnlineOrderItem"
            },
            "nullable": true,
            "description": "Die Positionen."
          },
          "subtotal": {
            "type": "number",
            "format": "double",
            "description": "Summe der Positionen."
          },
          "deliveryFee": {
            "type": "number",
            "format": "double",
            "description": "Liefergebühr."
          },
          "tipAmount": {
            "type": "number",
            "format": "double",
            "description": "Trinkgeld."
          },
          "grandTotal": {
            "type": "number",
            "format": "double",
            "description": "Gesamtbetrag."
          },
          "requestedTime": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wunschzeitpunkt des Gastes."
          },
          "estimatedReadyTime": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Voraussichtlich fertig."
          },
          "confirmedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Angenommen am."
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Abgeschlossen am."
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true,
            "description": "Zahlart (`cash`, `stripe`, `paypal`)."
          },
          "isPaid": {
            "type": "boolean",
            "description": "`true`: bezahlt."
          },
          "paidAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Bezahlt am."
          },
          "amountDue": {
            "type": "number",
            "format": "double",
            "description": "Noch zu zahlender Betrag."
          },
          "kitchenNotes": {
            "type": "string",
            "nullable": true,
            "description": "Hinweis für die Küche."
          },
          "rejectionReason": {
            "type": "string",
            "nullable": true,
            "description": "Grund bei Ablehnung oder Stornierung."
          },
          "guestSecret": {
            "type": "string",
            "nullable": true,
            "description": "Bestell-Geheimnis. **Nur in der Antwort von `create` gesetzt**, danach nie wieder; sofort speichern."
          }
        }
      },
      "OnlinePaymentInitResponse": {
        "type": "object",
        "description": "Daten zum Starten der Zahlung im Browser des Gastes.",
        "properties": {
          "provider": {
            "type": "string",
            "nullable": true,
            "description": "`stripe` oder `paypal`."
          },
          "clientSecret": {
            "type": "string",
            "nullable": true,
            "description": "Stripe: Client-Secret des Zahlungsvorgangs für Stripe.js. Bei PayPal leer."
          },
          "publishableKey": {
            "type": "string",
            "nullable": true,
            "description": "Stripe: öffentlicher Schlüssel des Betriebs für Stripe.js."
          },
          "paymentIntentId": {
            "type": "string",
            "nullable": true,
            "description": "Stripe: Kennung des Zahlungsvorgangs."
          },
          "redirectUrl": {
            "type": "string",
            "nullable": true,
            "description": "PayPal: Adresse, zu der der Gast weitergeleitet wird."
          }
        }
      },
      "OnlineShopConfigResponse": {
        "type": "object",
        "description": "Öffentliche Angaben zum Shop des Betriebs.",
        "properties": {
          "shopName": {
            "type": "string",
            "nullable": true,
            "description": "Name des Shops."
          },
          "shopDescription": {
            "type": "string",
            "nullable": true,
            "description": "Beschreibung."
          },
          "shopSlogan": {
            "type": "string",
            "nullable": true,
            "description": "Slogan."
          },
          "companyName": {
            "type": "string",
            "nullable": true,
            "description": "Firmenname."
          },
          "street": {
            "type": "string",
            "nullable": true,
            "description": "Straße und Hausnummer."
          },
          "zipCode": {
            "type": "string",
            "nullable": true,
            "description": "Postleitzahl."
          },
          "city": {
            "type": "string",
            "nullable": true,
            "description": "Ort."
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Land."
          },
          "phone": {
            "type": "string",
            "nullable": true,
            "description": "Telefon."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "description": "E-Mail-Adresse."
          },
          "openingHours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpeningHoursEntry"
            },
            "nullable": true,
            "description": "Öffnungszeiten je Wochentag."
          },
          "pickupEnabled": {
            "type": "boolean",
            "description": "Abholung wird angeboten."
          },
          "deliveryEnabled": {
            "type": "boolean",
            "description": "Lieferung wird angeboten."
          },
          "minOrderAmount": {
            "type": "number",
            "format": "double",
            "description": "Mindestbestellwert."
          },
          "orderLeadTimeMinutes": {
            "type": "integer",
            "format": "int32",
            "description": "Vorlaufzeit für Bestellungen in Minuten."
          },
          "maxScheduleDays": {
            "type": "integer",
            "format": "int32",
            "description": "Wie viele Tage im Voraus bestellt werden darf."
          },
          "stripeEnabled": {
            "type": "boolean",
            "description": "Kartenzahlung über Stripe ist eingeschaltet."
          },
          "payPalEnabled": {
            "type": "boolean",
            "description": "PayPal ist eingeschaltet."
          },
          "cashOnPickupEnabled": {
            "type": "boolean",
            "description": "Barzahlung bei Abholung ist erlaubt."
          },
          "cashOnDeliveryEnabled": {
            "type": "boolean",
            "description": "Barzahlung bei Lieferung ist erlaubt."
          },
          "prepaymentRequiredPickup": {
            "type": "boolean",
            "description": "Abholung nur mit Online-Zahlung."
          },
          "prepaymentRequiredDelivery": {
            "type": "boolean",
            "description": "Lieferung nur mit Online-Zahlung."
          }
        }
      },
      "OpeningHoursEntry": {
        "type": "object",
        "description": "Öffnungszeit eines Wochentags.",
        "properties": {
          "dayOfWeek": {
            "type": "integer",
            "format": "int32",
            "description": "Wochentag, `0` Sonntag bis `6` Samstag."
          },
          "isClosed": {
            "type": "boolean",
            "description": "`true`: an diesem Tag geschlossen."
          },
          "openTime": {
            "type": "string",
            "nullable": true,
            "description": "Öffnet (`11:00`)."
          },
          "closeTime": {
            "type": "string",
            "nullable": true,
            "description": "Schließt (`22:00`)."
          },
          "breakStart": {
            "type": "string",
            "nullable": true,
            "description": "Beginn der Pause, falls vorhanden."
          },
          "breakEnd": {
            "type": "string",
            "nullable": true,
            "description": "Ende der Pause."
          }
        }
      },
      "PartnerApiKeyCreatedResponse": {
        "type": "object",
        "description": "Ein Partner-Schlüssel mit dem Geheimnis; nur in den Antworten von Anlegen und Erneuern.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Kennung (`pak_…`)."
          },
          "keyId": {
            "type": "string",
            "description": "Öffentlicher Teil des Schlüssels (nach `dk1_`)."
          },
          "name": {
            "type": "string",
            "description": "Bezeichnung."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Die erlaubten Bereiche."
          },
          "apiUserId": {
            "type": "string",
            "description": "Der technische Benutzer."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "description": "Angelegt am."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Läuft ab am."
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Widerrufen am."
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Zuletzt benutzt am."
          },
          "previousValidUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Nach einer Erneuerung: bis wann das alte Geheimnis noch gilt."
          },
          "status": {
            "type": "string",
            "description": "`active`, `expired` oder `revoked`."
          },
          "key": {
            "type": "string",
            "description": "Der vollständige Schlüssel (`dk1_<Kennung>.<Geheimnis>`). Wird nicht gespeichert und nie wieder angezeigt."
          }
        }
      },
      "PartnerApiKeyResponse": {
        "type": "object",
        "description": "Ein Partner-Schlüssel, ohne Geheimnis.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Kennung (`pak_…`)."
          },
          "keyId": {
            "type": "string",
            "description": "Öffentlicher Teil des Schlüssels (nach `dk1_`)."
          },
          "name": {
            "type": "string",
            "description": "Bezeichnung."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Die erlaubten Bereiche."
          },
          "apiUserId": {
            "type": "string",
            "description": "Der technische Benutzer."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "description": "Angelegt am."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Läuft ab am."
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Widerrufen am."
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Zuletzt benutzt am."
          },
          "previousValidUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Nach einer Erneuerung: bis wann das alte Geheimnis noch gilt."
          },
          "status": {
            "type": "string",
            "description": "`active`, `expired` oder `revoked`."
          }
        }
      },
      "PartnerApiScopesResponse": {
        "type": "object",
        "description": "Die zulässigen Bereiche.",
        "properties": {
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Alle Bereiche."
          },
          "header": {
            "type": "string",
            "description": "Name der Kopfzeile, in der der Schlüssel gesendet wird."
          }
        }
      },
      "RejectRequest": {
        "type": "object",
        "description": "Grund der Ablehnung.",
        "properties": {
          "reason": {
            "type": "string",
            "nullable": true,
            "description": "Grund, wird in `rejectionReason` der Bestellung gespeichert. Nicht erzwungen, aber zu empfehlen: der Betrieb sieht ihn."
          }
        }
      },
      "RetryWebhookDeliveriesRequest": {
        "type": "object",
        "description": "Tote Zustellungen wiederholen.",
        "properties": {
          "ids": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "description": "Kennungen der Zustellungen; ohne Angabe alle toten."
          }
        }
      },
      "RotatePartnerApiKeyRequest": {
        "type": "object",
        "description": "Schlüssel erneuern.",
        "properties": {
          "expiresInDays": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Neue Gültigkeit in Tagen, 1 bis 400; ohne Angabe 365."
          }
        }
      },
      "RotateWebhookSecretRequest": {
        "type": "object",
        "description": "Geheimnis erneuern.",
        "properties": {
          "graceDays": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Wie viele Tage das alte Geheimnis daneben gilt, 1 bis 30; ohne Angabe 7."
          }
        }
      },
      "ShopStatusResponse": {
        "type": "object",
        "description": "Ob der Shop gerade annimmt.",
        "properties": {
          "isOpen": {
            "type": "boolean",
            "description": "`true`: innerhalb der Öffnungszeiten."
          },
          "currentCloseTime": {
            "type": "string",
            "nullable": true,
            "description": "Heutige Schließzeit (`22:00`), solange geöffnet."
          },
          "nextOpenDate": {
            "type": "string",
            "nullable": true,
            "description": "Datum der nächsten Öffnung (`2026-11-12`), wenn geschlossen."
          },
          "nextOpenClockTime": {
            "type": "string",
            "nullable": true,
            "description": "Uhrzeit der nächsten Öffnung (`11:00`), wenn geschlossen."
          },
          "nextOpenDaysAhead": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Tage bis zur nächsten Öffnung; `0` = heute noch."
          },
          "nextOpenTime": {
            "type": "string",
            "nullable": true,
            "description": "Veraltet: nächste Öffnung als fertiger deutscher Text. Neue Anbindungen verwenden `nextOpenDate` und `nextOpenClockTime`."
          }
        }
      },
      "UpdateStatusRequest": {
        "type": "object",
        "description": "Der neue Stand.",
        "properties": {
          "status": {
            "type": "integer",
            "format": "int32",
            "description": "Neuer Stand, `1` bis `10` (Werte siehe `status` der Bestellung)."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "description": "Grund; wird bei `9` und `10` als `rejectionReason` gespeichert."
          }
        },
        "required": [
          "status"
        ]
      },
      "UpdateWebhookTargetRequest": {
        "type": "object",
        "description": "Ziel ändern; fehlende Felder bleiben.",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Neue Bezeichnung."
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Neue Adresse; wird wie beim Anlegen geprüft."
          },
          "eventTypes": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "description": "Neue Ereignisarten."
          },
          "enabled": {
            "type": "boolean",
            "nullable": true,
            "description": "Ziel ein- oder ausschalten."
          }
        }
      },
      "WaitEstimateResponse": {
        "type": "object",
        "description": "Geschätzte Wartezeit aus der Küchenlast.",
        "properties": {
          "pickupMinutes": {
            "type": "integer",
            "format": "int32",
            "description": "Minuten bis zur Abholung."
          },
          "deliveryMinutes": {
            "type": "integer",
            "format": "int32",
            "description": "Minuten bis zur Lieferung."
          },
          "load": {
            "type": "string",
            "nullable": true,
            "description": "Auslastung der Küche: `low`, `normal` oder `high`."
          },
          "readyAt": {
            "type": "string",
            "format": "date-time",
            "description": "Voraussichtlich fertig (Abholung)."
          },
          "deliveryAt": {
            "type": "string",
            "format": "date-time",
            "description": "Voraussichtlich geliefert."
          },
          "acceptingOrders": {
            "type": "boolean",
            "description": "`false`: der Betrieb nimmt wegen Küchenlast gerade nicht an."
          }
        }
      },
      "WebhookDeliveryResponse": {
        "type": "object",
        "description": "Die Zustellung eines Ereignisses an ein Ziel.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Kennung der Zustellung."
          },
          "eventId": {
            "type": "string",
            "description": "Kennung des Ereignisses."
          },
          "targetId": {
            "type": "string",
            "description": "Kennung des Ziels."
          },
          "status": {
            "type": "string",
            "description": "`Offen`, `Erledigt` oder `Tot`."
          },
          "attempts": {
            "type": "integer",
            "format": "int32",
            "description": "Bisherige Versuche."
          },
          "nextAttemptAt": {
            "type": "string",
            "format": "date-time",
            "description": "Nächster Versuch."
          },
          "lastError": {
            "type": "string",
            "nullable": true,
            "description": "Fehlercode des letzten Versuchs (`HTTP_500`, `TIMEOUT`, `TLS`); nie ein Rumpf."
          },
          "lastHttpStatus": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "HTTP-Status der letzten Antwort des Empfängers."
          },
          "deliveredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Zugestellt am."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "description": "Angelegt am."
          }
        }
      },
      "WebhookEventResponse": {
        "type": "object",
        "description": "Ein Ereignis, wie es der Feed ausliefert und wie es an ein Webhook-Ziel gesendet wird.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Eindeutige Kennung (`<Bestellung>.<seq>`); Empfänger entdoppeln darüber.",
            "nullable": true
          },
          "type": {
            "type": "string",
            "description": "`order.created`, `order.status_changed`, `payment.received`, `order.cancelled` oder `ticket.ready`.",
            "nullable": true
          },
          "occurredAt": {
            "type": "string",
            "description": "Zeitpunkt (UTC).",
            "nullable": true
          },
          "tenant": {
            "type": "string",
            "description": "Kennung des Betriebs.",
            "nullable": true
          },
          "seq": {
            "type": "integer",
            "description": "Laufende Nummer je Bestellung (aufsteigend, lückenlos); darüber ordnen Empfänger und erkennen Lücken.",
            "format": "int32"
          },
          "apiVersion": {
            "type": "string",
            "description": "Version der Nutzlasten.",
            "nullable": true
          },
          "data": {
            "description": "Die Nutzlast je `type`, ohne personenbezogene Angaben; Einzelheiten holt der Empfänger mit seinem Schlüssel. Beispiele: `order.created`: `orderId`, `orderNumber`, `orderType`; `order.status_changed`: `orderId`, `orderNumber`, `status`, `previousStatus`, `isPaid`."
          }
        }
      },
      "WebhookEventsPageResponse": {
        "type": "object",
        "description": "Eine Seite des Ereignis-Feeds.",
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventResponse"
            },
            "description": "Die Ereignisse, aufsteigend nach Entstehung.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Zeiger für den nächsten Aufruf (`after`); immer gesetzt, auch ohne neue Ereignisse.",
            "nullable": true
          },
          "hasMore": {
            "type": "boolean",
            "description": "`true`: weitere Ereignisse liegen sofort bereit."
          }
        }
      },
      "WebhookTargetCreatedResponse": {
        "type": "object",
        "description": "Ein Webhook-Ziel mit dem Geheimnis; nur in den Antworten von Anlegen und Erneuern.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Kennung (`whz_…`)."
          },
          "name": {
            "type": "string",
            "description": "Bezeichnung."
          },
          "url": {
            "type": "string",
            "description": "https-Adresse des Empfängers."
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Gewünschte Ereignisarten; leer heißt alle."
          },
          "enabled": {
            "type": "boolean",
            "description": "`false`: das Ziel bekommt nichts; die Ereignisse bleiben im Feed."
          },
          "disabledReason": {
            "type": "string",
            "nullable": true,
            "description": "`GONE` (der Empfänger antwortete `410`) oder `MANUAL`; sonst leer."
          },
          "disabledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wann das Ziel abgeschaltet wurde."
          },
          "pausedUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wegen vieler Fehler in Folge pausiert bis."
          },
          "previousSecretValidUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Ende der Übergangsfrist des alten Geheimnisses nach einer Erneuerung."
          },
          "operatorException": {
            "type": "boolean",
            "description": "Der Betreiber hat für dieses Ziel ein privates Netz oder einen anderen Port freigegeben."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "description": "Angelegt am (UTC)."
          },
          "secret": {
            "type": "string",
            "description": "Das Geheimnis (`whsec_…`) zur Prüfung der Signatur. Wird nur in dieser Antwort ausgegeben."
          }
        }
      },
      "WebhookTargetResponse": {
        "type": "object",
        "description": "Ein Webhook-Ziel, ohne Geheimnis.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Kennung (`whz_…`)."
          },
          "name": {
            "type": "string",
            "description": "Bezeichnung."
          },
          "url": {
            "type": "string",
            "description": "https-Adresse des Empfängers."
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Gewünschte Ereignisarten; leer heißt alle."
          },
          "enabled": {
            "type": "boolean",
            "description": "`false`: das Ziel bekommt nichts; die Ereignisse bleiben im Feed."
          },
          "disabledReason": {
            "type": "string",
            "nullable": true,
            "description": "`GONE` (der Empfänger antwortete `410`) oder `MANUAL`; sonst leer."
          },
          "disabledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wann das Ziel abgeschaltet wurde."
          },
          "pausedUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wegen vieler Fehler in Folge pausiert bis."
          },
          "previousSecretValidUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Ende der Übergangsfrist des alten Geheimnisses nach einer Erneuerung."
          },
          "operatorException": {
            "type": "boolean",
            "description": "Der Betreiber hat für dieses Ziel ein privates Netz oder einen anderen Port freigegeben."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "description": "Angelegt am (UTC)."
          }
        }
      },
      "ValidationError": {
        "type": "object",
        "description": "Eine fehlerhafte Eingabe.",
        "properties": {
          "field": {
            "type": "string",
            "description": "Name des Feldes."
          },
          "message": {
            "type": "string",
            "description": "Was daran nicht stimmt."
          }
        }
      }
    }
  }
}
