{
  "openapi": "3.1.0",
  "info": {
    "title": "Fussmarke API",
    "version": "1.0.0",
    "summary": "Preise abrufen und unverbindliche Angebotsanfragen für Firmensocken mit Logo stellen",
    "description": "Schnittstelle von Fussmarke (Firmensocken mit eingestricktem Logo, ab 100 Paar, nur für Unternehmen, Vereine und öffentliche Einrichtungen in Deutschland). Es gibt keine Anmeldung, keine Bestellung und keine Zahlung über die API: Eine Anfrage ist kostenlos und unverbindlich, Fussmarke antwortet per E-Mail in der Regel innerhalb von 24 Stunden (werktags) mit Entwurf und Angebot. Alle Preise netto zzgl. USt.; maßgeblich ist das Angebot. Dieselben Funktionen gibt es als MCP-Server unter https://fussmarke.de/mcp (Tools produkt_info, preis_berechnen, angebot_anfragen). Anfragen bitte nur mit Zustimmung und echten Kontaktdaten des Nutzers senden.",
    "contact": {
      "name": "Tugay Kazarel, Fussmarke",
      "email": "anfrage@fussmarke.de",
      "url": "https://fussmarke.de/impressum"
    }
  },
  "servers": [
    {
      "url": "https://fussmarke.de",
      "description": "Produktion"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Überblick für KI-Agenten",
    "url": "https://fussmarke.de/llms.txt"
  },
  "tags": [
    {
      "name": "Preise",
      "description": "Preisstaffeln, Verpackungen und Lieferzeit"
    },
    {
      "name": "Anfrage",
      "description": "Kostenlose, unverbindliche Anfrage für Entwurf und Angebot"
    }
  ],
  "paths": {
    "/api/preise": {
      "get": {
        "operationId": "preiseAbrufen",
        "tags": ["Preise"],
        "summary": "Aktuelle Preise abrufen",
        "description": "Liefert die Preisliste als JSON (dieselben Werte wie auf der Website). Staffeln sind Listen aus [ab Menge, Preis netto pro Paar]; es gilt die höchste erreichte Stufe. Business, Quarter und Sneaker nutzen die Staffel standard, Sport die Staffel sport. Bei der 3-Paar-Box (verpackung.box3) zählt die Menge in Boxen à 3 Paar. Verpackungen mit anfrage: true haben einen Preis auf Anfrage.",
        "responses": {
          "200": {
            "description": "Preisliste",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Preise"
                }
              }
            }
          },
          "503": {
            "description": "Preisliste gerade nicht verfügbar",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Antwort"
                },
                "example": {
                  "ok": false,
                  "error": "Die Preisliste ist gerade nicht verfügbar."
                }
              }
            }
          }
        }
      }
    },
    "/api/anfrage": {
      "post": {
        "operationId": "angebotAnfragen",
        "tags": ["Anfrage"],
        "summary": "Unverbindliche Anfrage für Entwurf und Angebot senden",
        "description": "Schickt die Anfrage als E-Mail an Fussmarke. Bitte den Header Accept: application/json senden, dann antwortet der Server mit JSON; ohne ihn leitet er wie das Website-Formular mit 303 auf /danke um bzw. liefert Fehler als Text. Pflicht sind name, firma, email und telefon. Spam-Schutz: Das Feld website muss leer bleiben oder fehlen; das Feld t (Millisekunden seit Aufruf des Formulars) muss mindestens 3000 sein, sonst wird die Anfrage still verworfen und trotzdem {\"ok\": true} gemeldet. Agenten senden deshalb t mit einem Wert ab 3000, zum Beispiel 5000.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AnfrageMitDatei"
              },
              "encoding": {
                "logo": {
                  "contentType": "image/png, image/jpeg, image/svg+xml, application/pdf, application/postscript"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Anfrage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Anfrage angenommen. Fussmarke meldet sich per E-Mail, in der Regel innerhalb von 24 Stunden (werktags).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Antwort"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "303": {
            "description": "Ohne Accept: application/json: Weiterleitung auf die Dankeseite /danke (wie beim Website-Formular).",
            "headers": {
              "Location": {
                "description": "https://fussmarke.de/danke",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Fehler"
          },
          "413": {
            "$ref": "#/components/responses/Fehler"
          },
          "415": {
            "$ref": "#/components/responses/Fehler"
          },
          "422": {
            "$ref": "#/components/responses/Fehler"
          },
          "502": {
            "$ref": "#/components/responses/Fehler"
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Fehler": {
        "description": "Fehler: 400 Anfrage nicht lesbar, 413 Datei größer als 10 MB (bzw. alle Dateien zusammen zu groß), 415 falscher Dateityp, 422 Pflichtfeld fehlt oder E-Mail bzw. Telefon ungültig, 502 Versand fehlgeschlagen (dann bitte an anfrage@fussmarke.de schreiben).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Antwort"
            },
            "example": {
              "ok": false,
              "error": "Bitte Firma angeben."
            }
          }
        }
      }
    },
    "schemas": {
      "Anfrage": {
        "type": "object",
        "required": ["name", "firma", "email", "telefon"],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120,
            "description": "Vor- und Nachname der anfragenden Person"
          },
          "firma": {
            "type": "string",
            "maxLength": 160,
            "description": "Unternehmen, Verein oder Einrichtung"
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 200,
            "description": "Geschäftliche E-Mail-Adresse für Entwurf und Angebot (Antworten gehen an diese Adresse)"
          },
          "telefon": {
            "type": "string",
            "maxLength": 60,
            "description": "Telefonnummer mit Vorwahl, nur für Rückfragen, mindestens 6 Ziffern"
          },
          "anlass": {
            "type": "string",
            "maxLength": 80,
            "description": "Wofür die Socken sind (Freitext). Werte des Website-Formulars siehe examples.",
            "examples": [
              "Messe oder Event",
              "Kunden- oder Partnergeschenk",
              "Onboarding / Welcome",
              "Jubiläum oder Kick-off",
              "Firmensport (Tennis, Padel, Firmenlauf)",
              "Weihnachten",
              "Anderer Anlass"
            ]
          },
          "produkt": {
            "type": "string",
            "maxLength": 80,
            "description": "Gewünschte Verpackung (Freitext). Werte des Website-Formulars siehe examples.",
            "examples": [
              "Socken mit Banderole",
              "Socken mit Etikett",
              "Socken in Premium-Einzelbox",
              "3-Paar-Box mit Karte"
            ]
          },
          "gestaltung": {
            "type": "string",
            "maxLength": 80,
            "description": "Wer den Entwurf gestaltet (Freitext). Werte des Website-Formulars siehe examples.",
            "examples": [
              "Wie im Konfigurator gestaltet",
              "Fussmarke gestaltet frei",
              "Eigenes Design (Datei im Anhang)"
            ]
          },
          "menge": {
            "type": "string",
            "maxLength": 40,
            "description": "Ungefähre Menge als Text; Mindestmenge 100 Paar pro Design (bei der 3-Paar-Box 100 Boxen)",
            "examples": ["500 Paar", "Noch unklar"]
          },
          "termin": {
            "type": "string",
            "format": "date",
            "maxLength": 40,
            "description": "Wunschtermin als Datum JJJJ-MM-TT. Lieferzeit 4–6 Wochen ab Freigabe des Entwurfs; ob der Termin zu halten ist, steht im Angebot.",
            "examples": ["2027-03-15"]
          },
          "groessen": {
            "type": "string",
            "maxLength": 160,
            "description": "Größenaufteilung als Text, falls bekannt (Größen 35–40 und 41–46). Ohne Angabe schlägt Fussmarke einen Mix vor."
          },
          "nachricht": {
            "type": "string",
            "maxLength": 4000,
            "description": "Weitere Wünsche, zum Beispiel Sockenart, Farben, Logo-Position, Lieferadresse"
          },
          "seite": {
            "type": "string",
            "maxLength": 300,
            "description": "Herkunft der Anfrage (beim Formular der Pfad der Seite), optional"
          },
          "t": {
            "type": "integer",
            "minimum": 3000,
            "description": "Spam-Schutz: Millisekunden seit Aufruf des Formulars. Werte unter 3000 werden still verworfen. Agenten senden einen Wert ab 3000, zum Beispiel 5000.",
            "examples": [5000]
          },
          "website": {
            "type": "string",
            "maxLength": 0,
            "description": "Spam-Falle: muss leer bleiben oder fehlen"
          }
        }
      },
      "AnfrageMitDatei": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Anfrage"
          },
          {
            "type": "object",
            "properties": {
              "logo": {
                "type": "string",
                "contentMediaType": "application/octet-stream",
                "description": "Logo oder fertiges Design als Datei (PNG, JPG, SVG, PDF, AI oder EPS), höchstens 10 MB, optional"
              }
            }
          }
        ]
      },
      "Antwort": {
        "type": "object",
        "required": ["ok"],
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "true, wenn die Anfrage angenommen wurde"
          },
          "error": {
            "type": "string",
            "description": "Fehlermeldung auf Deutsch (nur bei ok: false)"
          }
        }
      },
      "Staffel": {
        "type": "array",
        "description": "Stufen [ab Menge, Preis netto in EUR], aufsteigend; es gilt die höchste erreichte Stufe",
        "items": {
          "type": "array",
          "prefixItems": [
            {
              "type": "integer",
              "description": "ab Menge (Paare bzw. Boxen)"
            },
            {
              "type": "number",
              "description": "Preis netto in EUR"
            }
          ],
          "minItems": 2,
          "maxItems": 2
        }
      },
      "Socke": {
        "type": "object",
        "required": ["staffel"],
        "properties": {
          "name": {
            "type": "string"
          },
          "staffel": {
            "$ref": "#/components/schemas/Staffel"
          }
        }
      },
      "Verpackung": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "hinweis": {
            "type": "string"
          },
          "min": {
            "type": "integer",
            "description": "Mindestmenge (Paare bzw. Boxen)"
          },
          "staffel": {
            "$ref": "#/components/schemas/Staffel",
            "description": "Aufpreis pro Paar bzw. pro Box"
          },
          "anfrage": {
            "type": "boolean",
            "description": "true: Preis auf Anfrage"
          },
          "paare": {
            "type": "integer",
            "description": "Paare pro Box (nur box3)"
          },
          "regulaer": {
            "type": "number",
            "description": "Regulärer Aufpreis nach Ende des Einführungsangebots"
          },
          "bis": {
            "type": "string",
            "description": "Ende des Einführungsangebots (TT.MM.JJJJ)"
          }
        }
      },
      "Preise": {
        "type": "object",
        "required": ["standard", "sport", "verpackung", "ust", "mindestmenge", "waehrung"],
        "properties": {
          "standard": {
            "$ref": "#/components/schemas/Socke"
          },
          "sport": {
            "$ref": "#/components/schemas/Socke"
          },
          "verpackung": {
            "type": "object",
            "description": "Verpackungen: banderole, etikett, einzelbox, box3",
            "additionalProperties": {
              "$ref": "#/components/schemas/Verpackung"
            }
          },
          "mengen": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Mengenstufen der Website"
          },
          "lieferzeitWochen": {
            "type": "integer",
            "description": "Obere Grenze der Lieferzeit ab Freigabe in Wochen"
          },
          "lieferzeitText": {
            "type": "string",
            "examples": ["4–6 Wochen"]
          },
          "pufferTage": {
            "type": "integer"
          },
          "ust": {
            "type": "number",
            "description": "Umsatzsteuersatz, z. B. 0.19"
          },
          "tipp": {
            "type": "integer",
            "description": "Menge mit dem Hinweis „Unser Tipp“"
          },
          "mindestmenge": {
            "type": "integer",
            "description": "Mindestmenge in Paaren pro Design"
          },
          "waehrung": {
            "type": "string",
            "const": "EUR"
          },
          "hinweis": {
            "type": "string",
            "examples": ["netto zzgl. USt."]
          },
          "sockenarten": {
            "type": "object",
            "description": "Sockenarten (business, sport, quarter, sneaker) mit Name und zugehöriger Staffel",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "staffel": {
                  "type": "string",
                  "enum": ["standard", "sport"]
                }
              }
            }
          }
        }
      }
    }
  }
}
