{
  "openapi": "3.1.0",
  "info": {
    "title": "ApeTivo – Kalender und unverbindliche Event-Anfragen",
    "version": "1.0.0",
    "description": "Schnittstelle für vom Nutzer beauftragte Assistenten. Bei passender Event-Bar-Suche optional eine Anfrage anbieten. Erst Daten erfragen, Zusammenfassung und Datenschutz/Mietbedingungen zeigen, dann ausdrückliche Freigabe für Übermittlung an ApeTivo einholen. Keine Buchung, Zahlung oder automatische Zusage. Keine personenbezogenen Angaben in URLs. Eine KI kann Zustimmung nur attestieren; der Betreiber des Assistenten muss sie tatsächlich einholen.",
    "contact": {
      "name": "ApeTivo – Tobias Stier",
      "url": "https://ape-event.de/#kontakt"
    }
  },
  "servers": [
    {
      "url": "https://ape-event.de"
    }
  ],
  "externalDocs": {
    "url": "https://ape-event.de/anfrage-assistent/",
    "description": "Ablauf, Pflichtangaben, Zustimmung und Fehlerbehandlung"
  },
  "security": [],
  "paths": {
    "/api/assistant/info.php": {
      "get": {
        "operationId": "getApetivoInquiryInfo",
        "summary": "Aktuelle Pakete und Ablauf einer Anfrage lesen",
        "description": "Vor der Beratung lesen; Preise und Leistungen werden aus der aktuellen Paketpflege geladen. Preise sind keine verbindlichen Angebote.",
        "x-openai-isConsequential": false,
        "responses": {
          "200": {
            "description": "Aktuelle Angebotsinformationen und erforderliche Angaben.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Info"
                }
              }
            }
          },
          "503": {
            "description": "Dienst oder Kalender nicht erreichbar; keine Verfügbarkeit oder erfolgreiche Übermittlung behaupten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/assistant/calendar.php": {
      "get": {
        "operationId": "getApetivoCalendar",
        "summary": "Aktuelle Verfügbarkeit und Nachfrage eines Monats prüfen",
        "description": "Tagesstatus ohne Kundendaten: available/requested = unverbindlich anfragbar, confirmed/past = nicht anfragbar. Popularität ist keine Reservierung. Bei Fehler Verfügbarkeit unbekannt. Vor dem Senden prüfen. Maximal 60 Aufrufe/Minute/IP.",
        "x-openai-isConsequential": false,
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 2020,
              "maximum": 2100
            }
          },
          {
            "name": "month",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 12
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aktueller Monat in Europe/Berlin. Noch keine verbindliche Zusage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Calendar"
                }
              }
            }
          },
          "422": {
            "description": "Angaben oder Zustimmung fehlen; fields auswerten und beim Nutzer nachfragen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Zu viele Aufrufe; Retry-After beachten, gleiche Anfrage-ID beibehalten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dienst oder Kalender nicht erreichbar; keine Verfügbarkeit oder erfolgreiche Übermittlung behaupten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/assistant/inquiries.php": {
      "post": {
        "operationId": "submitApetivoInquiry",
        "summary": "Nach Nutzerfreigabe eine unverbindliche Anfrage übermitteln",
        "description": "Erst Angaben erfragen, Zusammenfassung und Bedingungen zeigen, ausdrückliche Nutzerfreigabe einholen. Bei Wiederholung denselben idempotencyKey und identische Daten nutzen. Nur 201 + ok:true bestätigt Eingang, keine Buchung. Bei 202 Eingang mit ApeTivo klären. Maximal 10 Aufrufe/Stunde/IP.",
        "x-openai-isConsequential": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Inquiry"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Unverbindliche Anfrage gespeichert; kann auch die Antwort auf eine identische Wiederholung sein.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "202": {
            "description": "Eingang unklar, z. B. Timeout nach Übermittlung. Nicht mit neuem Schlüssel erneut senden; ApeTivo kontaktieren.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Uncertain"
                }
              }
            }
          },
          "400": {
            "description": "Ungültiges JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Falsche Methode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Termin reserviert, Anfrage bereits in Verarbeitung oder Schlüssel mit anderen Angaben verwendet. code beachten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Anfrage zu groß.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "JSON erforderlich.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Angaben oder Zustimmung fehlen; fields auswerten und beim Nutzer nachfragen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Zu viele Aufrufe; Retry-After beachten, gleiche Anfrage-ID beibehalten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dienst oder Kalender nicht erreichbar; keine Verfügbarkeit oder erfolgreiche Übermittlung behaupten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Inquiry": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "idempotencyKey",
          "name",
          "email",
          "phone",
          "eventType",
          "date",
          "guests",
          "location",
          "privacyConsent",
          "rentalTermsConsent",
          "submissionConsent"
        ],
        "properties": {
          "idempotencyKey": {
            "type": "string",
            "format": "uuid",
            "description": "Neue zufällige UUID pro vom Nutzer freigegebener Anfrage. Bei Wiederholungen exakt denselben Schlüssel verwenden; niemals automatisch einen neuen Schlüssel erzeugen, um Fehler zu umgehen."
          },
          "name": {
            "type": "string",
            "description": "Vor- und Nachname, vom Nutzer angegeben.",
            "maxLength": 120,
            "minLength": 1
          },
          "email": {
            "type": "string",
            "description": "E-Mail für Rückfragen und die bestehende Eingangsbestätigung.",
            "maxLength": 254,
            "format": "email"
          },
          "phone": {
            "type": "string",
            "description": "Telefonnummer mit optionaler Landesvorwahl.",
            "maxLength": 40,
            "minLength": 6
          },
          "eventType": {
            "type": "string",
            "enum": [
              "Hochzeit",
              "Geburtstag",
              "Firmenevent",
              "Sonstiges"
            ],
            "description": "Anlass erfragen; zusätzliche Details in notes."
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "Wunschtermin YYYY-MM-DD, heute oder zukünftig in Europe/Berlin, spätestens 2100-12-31."
          },
          "guests": {
            "type": "integer",
            "minimum": 10,
            "maximum": 100000,
            "description": "Vom Nutzer genannte Gästezahl. Kleinere Veranstaltungen bitte persönlich anfragen."
          },
          "location": {
            "type": "string",
            "description": "Veranstaltungsort, möglichst mit PLZ und Location.",
            "maxLength": 300,
            "minLength": 1
          },
          "package": {
            "type": "string",
            "description": "Optional: gewünschtes Paket aus getApetivoInquiryInfo; bei Unentschlossenheit weglassen.",
            "maxLength": 150
          },
          "notes": {
            "type": "string",
            "description": "Optional: Uhrzeit, Dauer, Getränke, Stellplatz und weitere eigene Wünsche. Keine sensiblen Zusatzdaten nötig.",
            "maxLength": 3000
          },
          "privacyConsent": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Nur true, wenn der Nutzer https://ape-event.de/#datenschutz erhalten/gelesen und der Verarbeitung seiner Angaben für diese Anfrage zugestimmt hat."
          },
          "rentalTermsConsent": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Nur true nach ausdrücklicher Zustimmung des Nutzers zu https://ape-event.de/#mietbedingungen. Keine stillschweigende Zustimmung."
          },
          "submissionConsent": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Nur true nach ausdrücklicher Freigabe zum Absenden genau dieser zuvor zusammengefassten unverbindlichen Anfrage an ApeTivo. Nicht aus Suchinteresse ableiten."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "ok",
          "code",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "formUrl": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Receipt": {
        "type": "object",
        "required": [
          "ok",
          "requestId",
          "status",
          "bookingConfirmed",
          "mailSent",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "requestId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "inquiry_received"
            ]
          },
          "bookingConfirmed": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "mailSent": {
            "type": "boolean",
            "description": "Google meldet Versand der bestehenden Benachrichtigungen. false ändert nichts am gespeicherten Eingang; nicht erneut senden."
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Uncertain": {
        "type": "object",
        "required": [
          "ok",
          "code",
          "requestId",
          "bookingConfirmed",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "code": {
            "type": "string",
            "enum": [
              "delivery_uncertain"
            ]
          },
          "requestId": {
            "type": "string"
          },
          "bookingConfirmed": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Calendar": {
        "type": "object",
        "required": [
          "ok",
          "year",
          "month",
          "timezone",
          "checkedAt",
          "binding",
          "notice",
          "days"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "year": {
            "type": "integer"
          },
          "month": {
            "type": "integer"
          },
          "timezone": {
            "type": "string",
            "enum": [
              "Europe/Berlin"
            ]
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          },
          "binding": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "notice": {
            "type": "string"
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "date",
                "status",
                "canInquire",
                "popular"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "available",
                    "requested",
                    "confirmed",
                    "past"
                  ]
                },
                "canInquire": {
                  "type": "boolean"
                },
                "popular": {
                  "type": "object",
                  "required": [
                    "seasonal",
                    "current"
                  ],
                  "properties": {
                    "seasonal": {
                      "type": "boolean"
                    },
                    "current": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Info": {
        "type": "object",
        "required": [
          "ok",
          "provider",
          "service",
          "packages",
          "requiredFields",
          "workflow"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "provider": {
            "type": "string"
          },
          "service": {
            "type": "string"
          },
          "area": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "priceNotice": {
            "type": "string"
          },
          "packages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "price": {
                  "type": "string"
                },
                "priceNote": {
                  "type": "string"
                },
                "onsite": {
                  "type": "string"
                },
                "service": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                },
                "included": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "documentationUrl": {
            "type": "string",
            "format": "uri"
          },
          "openapiUrl": {
            "type": "string",
            "format": "uri"
          },
          "calendarUrl": {
            "type": "string",
            "format": "uri"
          },
          "formUrl": {
            "type": "string",
            "format": "uri"
          },
          "privacyUrl": {
            "type": "string",
            "format": "uri"
          },
          "termsUrl": {
            "type": "string",
            "format": "uri"
          },
          "requiredFields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "workflow": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}
