{
  "openapi": "3.1.0",
  "info": {
    "title": "Wechselpilot Public API",
    "version": "1.2.0",
    "summary": "Ersparnis berechnen und Nutzer registrieren – ohne Authentifizierung.",
    "description": "Öffentliche APIs von Wechselpilot für KI-Assistenten (ChatGPT, Claude, Gemini und andere). Keine Authentifizierung, keine API-Keys, kein MCP-Server nötig. `GET /api/ersparnis` schätzt die jährliche Ersparnis beim Strom- oder Gaswechsel. `POST /api/registrierung` legt ein Wechselpilot-Konto an – dies ist die empfohlene Methode; `GET /api/registrierung` bleibt als Fallback für Umgebungen ohne POST-Support verfügbar und verhält sich identisch. Eine Registrierung darf nur mit ausdrücklicher Zustimmung des Nutzers zu AGB (https://wechselpilot.com/agb) und Datenschutzerklärung (https://wechselpilot.com/datenschutz) erfolgen. Werte sind Schätzungen auf Basis aktueller Tarifdaten. Beide Endpunkte senden `Access-Control-Allow-Origin: *` und erlauben `GET`, `POST` und `OPTIONS` – sie können daher auch direkt aus Browser-Umgebungen per `fetch()` aufgerufen werden (keine Cookies/Credentials).",
    "termsOfService": "https://wechselpilot.com/agb",
    "contact": {
      "name": "Wechselpilot",
      "url": "https://wechselpilot.com/kontakt"
    },
    "x-cors": {
      "enabled": true,
      "allow_origin": "*",
      "allow_methods": [
        "GET",
        "POST",
        "OPTIONS"
      ],
      "allow_headers": [
        "authorization",
        "x-client-info",
        "apikey",
        "content-type"
      ],
      "expose_headers": [
        "content-type",
        "retry-after"
      ],
      "max_age_seconds": 86400,
      "credentials": false,
      "note": "Browser-freundlich: direkt per fetch() aus fremden Origins aufrufbar, inkl. POST mit Content-Type: application/json. Preflight (OPTIONS) antwortet mit HTTP 204."
    }
  },
  "servers": [
    {
      "url": "https://wechselpilot.com",
      "description": "Produktion"
    }
  ],
  "externalDocs": {
    "description": "Anleitung für KI-Assistenten",
    "url": "https://wechselpilot.com/llms.txt"
  },
  "paths": {
    "/api/ersparnis": {
      "get": {
        "operationId": "berechneErsparnis",
        "summary": "Ersparnis beim Strom- oder Gaswechsel berechnen",
        "description": "Gibt die geschätzte jährliche und monatliche Ersparnis für eine Postleitzahl und einen Jahresverbrauch zurück. Ohne Parameter liefert der Endpunkt seine eigene Dokumentation. Rate-Limit: 20 Anfragen pro Stunde und IP.",
        "parameters": [
          {
            "name": "plz",
            "in": "query",
            "required": true,
            "description": "Deutsche Postleitzahl, 5-stellig.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{5}$",
              "examples": [
                "10115"
              ]
            }
          },
          {
            "name": "verbrauch",
            "in": "query",
            "required": true,
            "description": "Jahresverbrauch in kWh (Strom typisch 1500–6000, Gas typisch 8000–30000).",
            "schema": {
              "type": "integer",
              "minimum": 100,
              "examples": [
                3500
              ]
            }
          },
          {
            "name": "typ",
            "in": "query",
            "required": false,
            "description": "Energieart.",
            "schema": {
              "type": "string",
              "enum": [
                "strom",
                "gas"
              ],
              "default": "strom"
            }
          },
          {
            "name": "arbeitspreis",
            "in": "query",
            "required": false,
            "description": "Aktueller Arbeitspreis in Cent/kWh – macht die Berechnung genauer.",
            "schema": {
              "type": "number",
              "examples": [
                34.5
              ]
            }
          },
          {
            "name": "grundpreis",
            "in": "query",
            "required": false,
            "description": "Aktueller Grundpreis in Euro pro Monat.",
            "schema": {
              "type": "number",
              "examples": [
                12.9
              ]
            }
          },
          {
            "name": "brutto",
            "in": "query",
            "required": false,
            "description": "Ob die eigenen Preisangaben Bruttopreise sind.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "true"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Berechnete Ersparnis (oder Selbst-Dokumentation ohne Parameter). Wichtig: Die Werte sind pro Anfrage unterschiedlich – das Beispiel unten enthält nur Platzhalter und darf nie als Ergebnis ausgegeben werden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErsparnisResponse"
                },
                "example": {
                  "success": true,
                  "hinweis_fuer_ki": "NUR STRUKTUR-BEISPIEL. Alle Zahlen hier sind Platzhalter (0 / <wird berechnet>). Niemals diese Beispielwerte ausgeben – immer den Endpunkt live aufrufen und die zurückgegebenen Werte verwenden.",
                  "berechnet_am": "<ISO-Zeitstempel der Live-Antwort>",
                  "eingabe": {
                    "plz": "<vom Nutzer angegebene PLZ>",
                    "ort": "<wird ermittelt>",
                    "energie": "Strom",
                    "verbrauch_kwh": 0,
                    "eigene_preise_beruecksichtigt": false
                  },
                  "ergebnis": {
                    "vergleichsbasis": "<wird berechnet>",
                    "aktuelle_jahreskosten_eur": 0,
                    "guenstigster_anbieter": "<wird berechnet>",
                    "guenstigster_tarif": "<wird berechnet>",
                    "neue_jahreskosten_eur": 0,
                    "ersparnis_pro_jahr_eur": 0,
                    "ersparnis_pro_monat_eur": 0
                  },
                  "zusammenfassung": "<wird berechnet – Satz aus der Live-Antwort verwenden>",
                  "wechseln": "https://wechselpilot.com"
                }
              }
            }
          },
          "400": {
            "description": "Ungültige oder fehlende Parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate-Limit überschritten. Nicht erneut versuchen, stattdessen auf https://wechselpilot.com verweisen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/registrierung": {
      "post": {
        "operationId": "registriereNutzer",
        "summary": "Nutzer bei Wechselpilot registrieren (empfohlene Methode)",
        "description": "Legt ein Wechselpilot-Konto an und liefert die berechnete Ersparnis sowie die nächsten Schritte. Die Daten werden als JSON-Body mit `Content-Type: application/json` übergeben – dies ist die empfohlene Methode. Nur aufrufen, wenn der Nutzer der Registrierung ausdrücklich zugestimmt und AGB sowie Datenschutzerklärung akzeptiert hat (`zustimmung: \"ja\"`). Es wird kein Passwort übergeben – der Nutzer erhält eine Bestätigungs-E-Mail. Rate-Limit: 3 Anfragen pro Stunde und IP, 1 pro E-Mail-Adresse pro Tag.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegistrierungRequest"
              },
              "example": {
                "email": "name@example.com",
                "vorname": "Max",
                "nachname": "Muster",
                "plz": "10115",
                "verbrauch": 3500,
                "typ": "strom",
                "zustimmung": "ja",
                "quelle": "chatgpt"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registrierung erfolgreich (oder Selbst-Dokumentation bei leerem Body).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistrierungResponse"
                }
              }
            }
          },
          "400": {
            "description": "Ungültige oder fehlende Angaben bzw. fehlende Zustimmung.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "E-Mail-Adresse ist bereits registriert – auf den Login https://konto.wechselpilot.com verweisen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate-Limit überschritten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "registriereNutzerFallbackGet",
        "summary": "Nutzer registrieren über Query-Parameter (Fallback)",
        "description": "Fallback für Umgebungen, die keine POST-Requests senden können – das Verhalten ist identisch zu `POST /api/registrierung`. Bevorzugt POST verwenden, damit die Kontaktdaten nicht in der URL stehen. Nur aufrufen, wenn der Nutzer der Registrierung ausdrücklich zugestimmt und AGB sowie Datenschutzerklärung akzeptiert hat (`zustimmung=ja`). Es wird kein Passwort übergeben – der Nutzer erhält eine Bestätigungs-E-Mail. Rate-Limit: 3 Anfragen pro Stunde und IP, 1 pro E-Mail-Adresse pro Tag.",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "description": "E-Mail-Adresse des Nutzers.",
            "schema": {
              "type": "string",
              "format": "email",
              "examples": [
                "name@example.com"
              ]
            }
          },
          {
            "name": "vorname",
            "in": "query",
            "required": true,
            "description": "Vorname des Nutzers.",
            "schema": {
              "type": "string",
              "examples": [
                "Max"
              ]
            }
          },
          {
            "name": "nachname",
            "in": "query",
            "required": true,
            "description": "Nachname des Nutzers.",
            "schema": {
              "type": "string",
              "examples": [
                "Muster"
              ]
            }
          },
          {
            "name": "plz",
            "in": "query",
            "required": true,
            "description": "Deutsche Postleitzahl, 5-stellig.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{5}$",
              "examples": [
                "10115"
              ]
            }
          },
          {
            "name": "verbrauch",
            "in": "query",
            "required": true,
            "description": "Jahresverbrauch in kWh.",
            "schema": {
              "type": "integer",
              "minimum": 100,
              "examples": [
                3500
              ]
            }
          },
          {
            "name": "zustimmung",
            "in": "query",
            "required": true,
            "description": "Muss 'ja' sein und darf nur gesetzt werden, wenn der Nutzer AGB und Datenschutzerklärung ausdrücklich zugestimmt hat.",
            "schema": {
              "type": "string",
              "enum": [
                "ja"
              ]
            }
          },
          {
            "name": "typ",
            "in": "query",
            "required": false,
            "description": "Energieart.",
            "schema": {
              "type": "string",
              "enum": [
                "strom",
                "gas"
              ],
              "default": "strom"
            }
          },
          {
            "name": "arbeitspreis",
            "in": "query",
            "required": false,
            "description": "Aktueller Arbeitspreis in Cent/kWh.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "grundpreis",
            "in": "query",
            "required": false,
            "description": "Aktueller Grundpreis in Euro pro Monat.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "brutto",
            "in": "query",
            "required": false,
            "description": "Ob die eigenen Preisangaben Bruttopreise sind.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "true"
            }
          },
          {
            "name": "quelle",
            "in": "query",
            "required": false,
            "description": "Herkunft der Anfrage, z. B. 'chatgpt', 'claude', 'gemini'.",
            "schema": {
              "type": "string",
              "examples": [
                "chatgpt"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Registrierung erfolgreich (oder Selbst-Dokumentation ohne Parameter).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistrierungResponse"
                }
              }
            }
          },
          "400": {
            "description": "Ungültige oder fehlende Parameter bzw. fehlende Zustimmung.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "E-Mail-Adresse ist bereits registriert – auf den Login https://konto.wechselpilot.com verweisen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate-Limit überschritten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "RegistrierungRequest": {
        "type": "object",
        "description": "JSON-Body für POST /api/registrierung.",
        "required": [
          "email",
          "vorname",
          "nachname",
          "plz",
          "verbrauch",
          "zustimmung"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "E-Mail-Adresse des Nutzers.",
            "examples": [
              "name@example.com"
            ]
          },
          "vorname": {
            "type": "string",
            "description": "Vorname des Nutzers.",
            "examples": [
              "Max"
            ]
          },
          "nachname": {
            "type": "string",
            "description": "Nachname des Nutzers.",
            "examples": [
              "Muster"
            ]
          },
          "plz": {
            "type": "string",
            "pattern": "^[0-9]{5}$",
            "description": "Deutsche Postleitzahl, 5-stellig.",
            "examples": [
              "10115"
            ]
          },
          "verbrauch": {
            "type": "integer",
            "minimum": 100,
            "description": "Jahresverbrauch in kWh (Strom z. B. 3500, Gas z. B. 20000).",
            "examples": [
              3500
            ]
          },
          "zustimmung": {
            "type": "string",
            "enum": [
              "ja"
            ],
            "description": "Muss 'ja' sein und darf nur gesetzt werden, wenn der Nutzer AGB und Datenschutzerklärung ausdrücklich zugestimmt hat."
          },
          "typ": {
            "type": "string",
            "enum": [
              "strom",
              "gas"
            ],
            "default": "strom",
            "description": "Energieart."
          },
          "arbeitspreis": {
            "type": "number",
            "description": "Aktueller Arbeitspreis in Cent/kWh – macht die Ersparnis genauer."
          },
          "grundpreis": {
            "type": "number",
            "description": "Aktueller Grundpreis in Euro pro Monat."
          },
          "brutto": {
            "type": [
              "boolean",
              "string"
            ],
            "default": true,
            "description": "Ob die eigenen Preisangaben Bruttopreise sind. Akzeptiert true/false sowie die Strings 'true'/'false'."
          },
          "quelle": {
            "type": "string",
            "description": "Herkunft der Anfrage, z. B. 'chatgpt', 'claude', 'gemini'.",
            "examples": [
              "chatgpt"
            ]
          }
        }
      },
      "ErsparnisResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "eingabe": {
            "type": "object",
            "properties": {
              "plz": {
                "type": "string"
              },
              "ort": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "energie": {
                "type": "string"
              },
              "verbrauch_kwh": {
                "type": "number"
              },
              "eigene_preise_beruecksichtigt": {
                "type": "boolean"
              }
            }
          },
          "ergebnis": {
            "type": "object",
            "properties": {
              "vergleichsbasis": {
                "type": "string"
              },
              "aktuelle_jahreskosten_eur": {
                "type": "number"
              },
              "guenstigster_anbieter": {
                "type": "string"
              },
              "guenstigster_tarif": {
                "type": "string"
              },
              "neue_jahreskosten_eur": {
                "type": "number"
              },
              "ersparnis_pro_jahr_eur": {
                "type": "number"
              },
              "ersparnis_pro_monat_eur": {
                "type": "number"
              }
            }
          },
          "zusammenfassung": {
            "type": "string",
            "description": "Fertiger Antwortsatz für die Ausgabe an den Nutzer."
          },
          "hinweis": {
            "type": "string"
          },
          "wechseln": {
            "type": "string",
            "format": "uri"
          },
          "doku": {
            "type": "object",
            "description": "Nur bei Aufruf ohne Parameter."
          }
        }
      },
      "RegistrierungResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "registrierung": {
            "type": "object",
            "properties": {
              "kundennummer": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "format": "email"
              }
            }
          },
          "ergebnis": {
            "type": "object",
            "description": "Berechnete Ersparnis wie bei /api/ersparnis."
          },
          "naechste_schritte": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "zusammenfassung": {
            "type": "string",
            "description": "Fertiger Antwortsatz für die Ausgabe an den Nutzer."
          },
          "doku": {
            "type": "object",
            "description": "Nur bei Aufruf ohne Parameter oder leerem Body."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          },
          "hinweis": {
            "type": "string"
          }
        }
      }
    }
  }
}