{
  "openapi": "3.1.0",
  "info": {
    "title": "sora.de Preisrechner für Maßanfertigungen",
    "version": "1.0.0",
    "summary": "Read-only price calculator for custom-made acrylic hoods, display cases, shelves, stairs, collection boxes and cut-to-size acrylic from sora.de.",
    "description": "Berechnet den Preis für Wunschmaße — exakt der Preis, den der Konfigurator auf sora.de und der Warenkorb ausweisen (gerundeter Endpreis brutto in EUR inkl. 19 % MwSt., ohne Versand). Nur lesend: bestellt wird im Shop über den konfigurator_link der Antwort. Keine Preisfaktoren, keine Aufschlüsselung. Maßanfertigungen sind vom Widerrufsrecht ausgeschlossen (§ 312g Abs. 2 Nr. 1 BGB). English: GET /preisrechner/v1/preis?typ=masshaube&breite=30&tiefe=20&hoehe=20 returns the gross price in EUR (hood with inner width 30, depth 20, height 20 cm). Begriffe: Maßhaube = Acrylhaube = Plexiglashaube. Übersicht für Menschen: https://www.sora.de/fuer-ki-assistenten",
    "contact": {
      "name": "sora.de GmbH",
      "email": "info@sora.de",
      "url": "https://www.sora.de/kontakt.html"
    },
    "license": {
      "name": "Freie Nutzung für Preisauskünfte (Quellenangabe und konfigurator_link erbeten)",
      "url": "https://www.sora.de/fuer-ki-assistenten"
    }
  },
  "servers": [
    {
      "url": "https://www.sora.de"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Für KI-Assistenten (Beschreibung, Beispiele, Limits)",
    "url": "https://www.sora.de/fuer-ki-assistenten"
  },
  "paths": {
    "/preisrechner/v1/produkte": {
      "get": {
        "operationId": "listeProdukte",
        "summary": "Produkttypen, Maßgrenzen, Optionen und Einheiten",
        "description": "Maschinenlesbare Liste aller berechenbaren Produkte inkl. Parameter, erlaubter Werte, Einheiten (cm/mm) und Maßgrenzen.",
        "responses": {
          "200": {
            "description": "Produktliste",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Ratenlimit: 60 Anfragen/Minute und 1500/Tag je IP. Header Retry-After beachten.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/preisrechner/v1/preis": {
      "get": {
        "operationId": "berechnePreisGet",
        "summary": "Preis für ein Wunschmaß (GET — für einfache Browse-Tools)",
        "description": "Beispiel: /preisrechner/v1/preis?typ=masshaube&breite=30&tiefe=20&hoehe=20&rueckwand=transparent&menge=1 . Maße in cm (Hauben, Spendenbox, Treppe, Vitrinen) bzw. mm (Actionfiguren-Case, Zuschnitte).",
        "parameters": [
          {
            "name": "typ",
            "in": "query",
            "required": true,
            "description": "Produkttyp. Auch akzeptiert: alternative Namen (z. B. acrylhaube, plexiglashaube, vitrine, zuschnitt) — siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "masshaube",
                "plattenspieler",
                "uebergroesse",
                "tunnel",
                "tunnel-uebergroesse",
                "spendenbox",
                "motu",
                "treppe",
                "mehrfachvitrine",
                "mehrfachvitrine-uebergroesse",
                "cd-regal",
                "golfball",
                "zuschnitt-rechteckig",
                "zuschnitt-kreisfoermig"
              ]
            }
          },
          {
            "name": "breite",
            "in": "query",
            "required": false,
            "description": "Innenbreite. Einheit: cm. Gilt für: masshaube, plattenspieler, uebergroesse, tunnel, tunnel-uebergroesse, spendenbox, motu, treppe, mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball, zuschnitt-rechteckig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "tiefe",
            "in": "query",
            "required": false,
            "description": "Innentiefe. Einheit: cm. Gilt für: masshaube, plattenspieler, uebergroesse, tunnel, tunnel-uebergroesse, spendenbox, motu, treppe, mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "hoehe",
            "in": "query",
            "required": false,
            "description": "Innenhöhe. Einheit: cm. Gilt für: masshaube, plattenspieler, uebergroesse, tunnel, tunnel-uebergroesse, spendenbox, motu, treppe, mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball, zuschnitt-rechteckig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "menge",
            "in": "query",
            "required": false,
            "description": "Stückzahl (1–99). Bei Zuschnitten und Actionfiguren-Cases sinkt der Stückpreis mit der Menge (Rüstkosten fallen nur einmal an). Gilt für: masshaube, plattenspieler, uebergroesse, tunnel, tunnel-uebergroesse, spendenbox, motu, treppe, mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball, zuschnitt-rechteckig, zuschnitt-kreisfoermig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 99
            }
          },
          {
            "name": "bodenart",
            "in": "query",
            "required": false,
            "description": "Bodenplatte: kein Boden, „standard\" (Stülpversion, steht seitlich über) oder „buendig\" (ohne Überstand), transparent oder schwarz. Ein Boden verringert die nutzbare Innenhöhe. Gilt für: masshaube, plattenspieler, uebergroesse, tunnel, tunnel-uebergroesse. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "kein-boden",
                "standard-transparent",
                "standard-schwarz",
                "buendig-transparent",
                "buendig-schwarz"
              ]
            }
          },
          {
            "name": "rueckwand",
            "in": "query",
            "required": false,
            "description": "Rückwand: transparent (Standard), schwarz oder verspiegelt (Aufpreis). Gilt für: masshaube, plattenspieler, uebergroesse, tunnel, tunnel-uebergroesse, spendenbox, mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "transparent",
                "schwarz",
                "verspiegelt"
              ]
            }
          },
          {
            "name": "kabelausschnitt",
            "in": "query",
            "required": false,
            "description": "Kabelausschnitt in der Rückwand. Bei „ja\" sind ausschnittbreite, ausschnitthoehe und ausschnittposition Pflicht. Gilt für: plattenspieler. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "ja",
                "nein"
              ]
            }
          },
          {
            "name": "ausschnittbreite",
            "in": "query",
            "required": false,
            "description": "Breite des Kabelausschnitts. Einheit: mm. Gilt für: plattenspieler. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "ausschnitthoehe",
            "in": "query",
            "required": false,
            "description": "Höhe des Kabelausschnitts. Einheit: mm. Gilt für: plattenspieler. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "ausschnittposition",
            "in": "query",
            "required": false,
            "description": "Abstand des Ausschnitts von der linken Kante. Einheit: mm. Gilt für: plattenspieler. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "deckel",
            "in": "query",
            "required": false,
            "description": "Deckel lose aufgelegt oder verschraubt (aufpreisfrei). Gilt für: spendenbox. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "lose",
                "verschraubt"
              ]
            }
          },
          {
            "name": "wandaufhaengung",
            "in": "query",
            "required": false,
            "description": "Aufhängung für die Wand (aufpreisfrei). Gilt für: spendenbox. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "ja",
                "nein"
              ]
            }
          },
          {
            "name": "schlitzbreite",
            "in": "query",
            "required": false,
            "description": "Breite des Einwurfschlitzes (nur zusammen mit schlitztiefe). Einheit: mm. Gilt für: spendenbox. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "schlitztiefe",
            "in": "query",
            "required": false,
            "description": "Tiefe des Einwurfschlitzes (nur zusammen mit schlitzbreite). Einheit: mm. Gilt für: spendenbox. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "abstand",
            "in": "query",
            "required": false,
            "description": "Abstand der Figur zur Rückwand (höchstens Tiefe − 10 mm); aufpreisfrei. Einheit: mm. Gilt für: motu. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "blister",
            "in": "query",
            "required": false,
            "description": "Blister-Halterung (aufpreisfrei; über 500 mm Breite/Höhe nicht möglich). Gilt für: motu. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "keine",
                "einfacher-rahmen",
                "doppelter-rahmen",
                "leiste"
              ]
            }
          },
          {
            "name": "stufen",
            "in": "query",
            "required": false,
            "description": "Anzahl Stufen (Stufentiefe und -höhe müssen Mindestwerte erreichen, sonst nennt die Fehlermeldung die Grenze). Gilt für: treppe. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "integer",
              "minimum": 2,
              "maximum": 30
            }
          },
          {
            "name": "stufenfronten",
            "in": "query",
            "required": false,
            "description": "Material der Stufenfronten (schwarz/verspiegelt mit Aufpreis). Gilt für: treppe. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "transparent",
                "schwarz",
                "verspiegelt"
              ]
            }
          },
          {
            "name": "spalten",
            "in": "query",
            "required": false,
            "description": "Anzahl Spalten (senkrechte Teilung). Breite Vitrinen brauchen mehrere Spalten, sonst biegen sich die Böden durch. Gilt für: mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 12
            }
          },
          {
            "name": "fachanzahl",
            "in": "query",
            "required": false,
            "description": "Anzahl Fächer/Ebenen je Spalte (übereinander). Gilt für: mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 16
            }
          },
          {
            "name": "frontplatte",
            "in": "query",
            "required": false,
            "description": "Frontplatte (Vitrine) oder offen (Regal). Gilt für: mehrfachvitrine, mehrfachvitrine-uebergroesse, cd-regal, golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "mit",
                "ohne"
              ]
            }
          },
          {
            "name": "golfball_modus",
            "in": "query",
            "required": false,
            "description": "Kugelzahl je Fach automatisch (maximal) oder manuell vorgeben. Gilt für: golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "automatisch",
                "manuell"
              ]
            }
          },
          {
            "name": "golfbaelle",
            "in": "query",
            "required": false,
            "description": "Kugeln je Fach (nur bei golfball_modus=manuell). Beeinflusst den Preis nicht. Gilt für: golfball. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          },
          {
            "name": "material",
            "in": "query",
            "required": false,
            "description": "Material und Stärke des Zuschnitts. Gilt für: zuschnitt-rechteckig, zuschnitt-kreisfoermig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "transparent-3mm",
                "transparent-4mm",
                "schwarz",
                "verspiegelt"
              ]
            }
          },
          {
            "name": "abgerundete_ecken",
            "in": "query",
            "required": false,
            "description": "Abgerundete Ecken (aufpreisfrei). Bei „ja\" ist eckradius Pflicht. Gilt für: zuschnitt-rechteckig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "string",
              "enum": [
                "ja",
                "nein"
              ]
            }
          },
          {
            "name": "eckradius",
            "in": "query",
            "required": false,
            "description": "Eckradius (höchstens die halbe Breite und die halbe Höhe). Einheit: mm. Gilt für: zuschnitt-rechteckig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "durchmesser",
            "in": "query",
            "required": false,
            "description": "Durchmesser. Einheit: mm. Gilt für: zuschnitt-kreisfoermig. Pflichtangaben je Typ: siehe /produkte.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Preis",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "produkt",
                    "preis",
                    "lieferzeit",
                    "versand",
                    "konfigurator_link"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "produkt": {
                      "type": "object",
                      "properties": {
                        "typ": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "artikelnummer": {
                          "type": "string"
                        }
                      }
                    },
                    "eingabe": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Die verwendete Eingabe inkl. Standardwerten."
                    },
                    "preis": {
                      "type": "object",
                      "properties": {
                        "gesamt_brutto": {
                          "type": "number",
                          "description": "Gerundeter Endpreis für die gesamte Menge, brutto, EUR."
                        },
                        "stueck_brutto": {
                          "type": "number"
                        },
                        "menge": {
                          "type": "integer"
                        },
                        "waehrung": {
                          "type": "string",
                          "const": "EUR"
                        },
                        "mwst": {
                          "type": "string"
                        },
                        "hinweis": {
                          "type": "string"
                        }
                      }
                    },
                    "lieferzeit": {
                      "type": "string",
                      "examples": [
                        "ca. 8 Werktage"
                      ]
                    },
                    "versand": {
                      "type": "object",
                      "properties": {
                        "ab_brutto": {
                          "type": "number"
                        },
                        "waehrung": {
                          "type": "string"
                        },
                        "gilt_fuer": {
                          "type": "string"
                        },
                        "nur_deutschland": {
                          "type": "boolean"
                        },
                        "hinweis": {
                          "type": "string"
                        }
                      }
                    },
                    "aussenmasse": {
                      "type": "object",
                      "description": "Außenmaße (nur Hauben, Spendenbox, Actionfiguren-Case)."
                    },
                    "fach_innenmasse_cm": {
                      "type": "object",
                      "description": "Nutzbarer Platz je Fach (nur Vitrinen/Regale)."
                    },
                    "hinweise": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "konfigurator_link": {
                      "type": "string",
                      "format": "uri",
                      "description": "Vorbefüllter Konfigurator — dem Kunden nennen, damit er direkt bestellen kann."
                    },
                    "quelle": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ungültige oder fehlende Parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Maße/Optionen sind für dieses Produkt nicht möglich (z. B. „max. 110 cm\"); die Meldung nennt die Grenze, ggf. mit vorschlag_typ.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Ratenlimit: 60 Anfragen/Minute und 1500/Tag je IP. Header Retry-After beachten.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Rechner vorübergehend nicht erreichbar oder ausgelastet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "berechnePreisPost",
        "summary": "Preis für ein Wunschmaß (POST mit JSON)",
        "description": "Gleiche Parameter wie GET als JSON-Objekt. Kein CORS (nur für Server-/Agent-Aufrufe).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "typ"
                ],
                "properties": {
                  "typ": {
                    "type": "string",
                    "enum": [
                      "masshaube",
                      "plattenspieler",
                      "uebergroesse",
                      "tunnel",
                      "tunnel-uebergroesse",
                      "spendenbox",
                      "motu",
                      "treppe",
                      "mehrfachvitrine",
                      "mehrfachvitrine-uebergroesse",
                      "cd-regal",
                      "golfball",
                      "zuschnitt-rechteckig",
                      "zuschnitt-kreisfoermig"
                    ]
                  },
                  "breite": {
                    "type": "number",
                    "minimum": 0
                  },
                  "tiefe": {
                    "type": "number",
                    "minimum": 0
                  },
                  "hoehe": {
                    "type": "number",
                    "minimum": 0
                  },
                  "menge": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 99
                  },
                  "bodenart": {
                    "type": "string",
                    "enum": [
                      "kein-boden",
                      "standard-transparent",
                      "standard-schwarz",
                      "buendig-transparent",
                      "buendig-schwarz"
                    ]
                  },
                  "rueckwand": {
                    "type": "string",
                    "enum": [
                      "transparent",
                      "schwarz",
                      "verspiegelt"
                    ]
                  },
                  "kabelausschnitt": {
                    "type": "string",
                    "enum": [
                      "ja",
                      "nein"
                    ]
                  },
                  "ausschnittbreite": {
                    "type": "number",
                    "minimum": 0
                  },
                  "ausschnitthoehe": {
                    "type": "number",
                    "minimum": 0
                  },
                  "ausschnittposition": {
                    "type": "number",
                    "minimum": 0
                  },
                  "deckel": {
                    "type": "string",
                    "enum": [
                      "lose",
                      "verschraubt"
                    ]
                  },
                  "wandaufhaengung": {
                    "type": "string",
                    "enum": [
                      "ja",
                      "nein"
                    ]
                  },
                  "schlitzbreite": {
                    "type": "number",
                    "minimum": 0
                  },
                  "schlitztiefe": {
                    "type": "number",
                    "minimum": 0
                  },
                  "abstand": {
                    "type": "number",
                    "minimum": 0
                  },
                  "blister": {
                    "type": "string",
                    "enum": [
                      "keine",
                      "einfacher-rahmen",
                      "doppelter-rahmen",
                      "leiste"
                    ]
                  },
                  "stufen": {
                    "type": "integer",
                    "minimum": 2,
                    "maximum": 30
                  },
                  "stufenfronten": {
                    "type": "string",
                    "enum": [
                      "transparent",
                      "schwarz",
                      "verspiegelt"
                    ]
                  },
                  "spalten": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 12
                  },
                  "fachanzahl": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 16
                  },
                  "frontplatte": {
                    "type": "string",
                    "enum": [
                      "mit",
                      "ohne"
                    ]
                  },
                  "golfball_modus": {
                    "type": "string",
                    "enum": [
                      "automatisch",
                      "manuell"
                    ]
                  },
                  "golfbaelle": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 50
                  },
                  "material": {
                    "type": "string",
                    "enum": [
                      "transparent-3mm",
                      "transparent-4mm",
                      "schwarz",
                      "verspiegelt"
                    ]
                  },
                  "abgerundete_ecken": {
                    "type": "string",
                    "enum": [
                      "ja",
                      "nein"
                    ]
                  },
                  "eckradius": {
                    "type": "number",
                    "minimum": 0
                  },
                  "durchmesser": {
                    "type": "number",
                    "minimum": 0
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preis",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "produkt",
                    "preis",
                    "lieferzeit",
                    "versand",
                    "konfigurator_link"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "produkt": {
                      "type": "object",
                      "properties": {
                        "typ": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "artikelnummer": {
                          "type": "string"
                        }
                      }
                    },
                    "eingabe": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Die verwendete Eingabe inkl. Standardwerten."
                    },
                    "preis": {
                      "type": "object",
                      "properties": {
                        "gesamt_brutto": {
                          "type": "number",
                          "description": "Gerundeter Endpreis für die gesamte Menge, brutto, EUR."
                        },
                        "stueck_brutto": {
                          "type": "number"
                        },
                        "menge": {
                          "type": "integer"
                        },
                        "waehrung": {
                          "type": "string",
                          "const": "EUR"
                        },
                        "mwst": {
                          "type": "string"
                        },
                        "hinweis": {
                          "type": "string"
                        }
                      }
                    },
                    "lieferzeit": {
                      "type": "string",
                      "examples": [
                        "ca. 8 Werktage"
                      ]
                    },
                    "versand": {
                      "type": "object",
                      "properties": {
                        "ab_brutto": {
                          "type": "number"
                        },
                        "waehrung": {
                          "type": "string"
                        },
                        "gilt_fuer": {
                          "type": "string"
                        },
                        "nur_deutschland": {
                          "type": "boolean"
                        },
                        "hinweis": {
                          "type": "string"
                        }
                      }
                    },
                    "aussenmasse": {
                      "type": "object",
                      "description": "Außenmaße (nur Hauben, Spendenbox, Actionfiguren-Case)."
                    },
                    "fach_innenmasse_cm": {
                      "type": "object",
                      "description": "Nutzbarer Platz je Fach (nur Vitrinen/Regale)."
                    },
                    "hinweise": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "konfigurator_link": {
                      "type": "string",
                      "format": "uri",
                      "description": "Vorbefüllter Konfigurator — dem Kunden nennen, damit er direkt bestellen kann."
                    },
                    "quelle": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ungültige oder fehlende Parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Maße/Optionen sind für dieses Produkt nicht möglich (z. B. „max. 110 cm\"); die Meldung nennt die Grenze, ggf. mit vorschlag_typ.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Ratenlimit: 60 Anfragen/Minute und 1500/Tag je IP. Header Retry-After beachten.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Rechner vorübergehend nicht erreichbar oder ausgelastet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "fehler"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "fehler": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "meldung": {
                          "type": "string"
                        },
                        "vorschlag_typ": {
                          "type": "string"
                        },
                        "vorschlag": {
                          "type": "string"
                        }
                      },
                      "additionalProperties": true
                    },
                    "dokumentation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
