{
  "openapi": "3.1.0",
  "info": {
    "title": "Ist deine Website bereit für KI-Agenten? – Scan-API",
    "version": "1.0.0",
    "description": "Prüft Websites auf ihre Bereitschaft für KI-Agenten: 23 Checks in 5 Kategorien (Auffindbarkeit, Inhalt, Bot-Zugriffskontrolle, API-/Auth-/MCP- & Skill-Erkennung, Commerce) und ein Bereitschafts-Level von 0 bis 5. Pro IP-Adresse gilt ein Rate-Limit.",
    "contact": {
      "name": "Online-Marketing.ai",
      "url": "https://online-marketing.ai"
    }
  },
  "servers": [
    {
      "url": "https://check.online-marketing.ai"
    }
  ],
  "paths": {
    "/api/scan": {
      "post": {
        "operationId": "scanSite",
        "summary": "Website auf Agent-Bereitschaft prüfen",
        "description": "Scannt die angegebene URL und liefert das Ergebnis aller Checks. Mit `format: \"agent\"` erhältst du stattdessen eine Markdown-Liste der fehlgeschlagenen Checks inkl. Lösungshinweisen.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScanRequest"
              },
              "examples": {
                "einfach": {
                  "summary": "Vollständiger Scan",
                  "value": {
                    "url": "https://www.beispiel.de"
                  }
                },
                "agent": {
                  "summary": "Markdown für KI-Agenten",
                  "value": {
                    "url": "https://www.beispiel.de",
                    "format": "agent"
                  }
                },
                "auswahl": {
                  "summary": "Nur ausgewählte Checks",
                  "value": {
                    "url": "https://www.beispiel.de",
                    "enabledChecks": [
                      "robotsTxt",
                      "sitemap",
                      "markdownNegotiation"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan abgeschlossen (auch wenn die Website selbst einen Fehler lieferte, siehe `siteError`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                },
                "example": "# Website-Analyse: https://www.beispiel.de\n\nScore: 2/5 (Bot-bewusst)\n\n---\n\nErstellt mit dem kostenlosen Agent-Readiness-Check von Online-Marketing.ai – https://check.online-marketing.ai"
              }
            }
          },
          "400": {
            "description": "Ungültige Anfrage (fehlende oder ungültige URL, ungültiger JSON-Body).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Ungültige URL angegeben"
                }
              }
            }
          },
          "413": {
            "description": "Anfrage-Body größer als 16 KB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Anfrage zu groß (maximal 16 KB)"
                }
              }
            }
          },
          "429": {
            "description": "Rate-Limit überschritten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Zu viele Anfragen. Bitte versuche es später erneut."
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Sekunden bis zur nächsten erlaubten Anfrage",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "500": {
            "description": "Interner Fehler beim Scannen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Interner Fehler beim Scannen. Bitte versuche es später erneut."
                }
              }
            }
          },
          "503": {
            "description": "Alle Scan-Plätze sind belegt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Der Scanner ist gerade ausgelastet. Bitte versuche es in einer Minute erneut."
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Sekunden bis zum nächsten Versuch",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Statusprüfung des Dienstes",
        "description": "Liefert `status: \"ok\"` und den aktuellen Zeitstempel, solange der Dienst läuft.",
        "responses": {
          "200": {
            "description": "Dienst ist erreichbar.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "timestamp"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "const": "ok"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Fehlermeldung auf Deutsch"
          }
        }
      },
      "ScanRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "Zu prüfende URL (ohne Schema wird https:// ergänzt).",
            "examples": [
              "https://www.beispiel.de"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "json",
              "agent"
            ],
            "default": "json",
            "description": "Antwortformat: JSON (Standard) oder Markdown für Agenten."
          },
          "enabledChecks": {
            "type": "array",
            "description": "Nur diese Checks ausführen (alle anderen werden als „ausgeschlossen“ gemeldet). Unbekannte IDs werden ignoriert. Ohne Angabe laufen alle 23 Checks.",
            "items": {
              "type": "string",
              "enum": [
                "robotsTxt",
                "sitemap",
                "linkHeaders",
                "dnsAid",
                "markdownNegotiation",
                "robotsTxtAiRules",
                "contentSignals",
                "webBotAuth",
                "apiCatalog",
                "oauthDiscovery",
                "oauthProtectedResource",
                "authMd",
                "mcpServerCard",
                "a2aAgentCard",
                "agentSkills",
                "webMcp",
                "ard",
                "personalAgentProtocol",
                "x402",
                "mpp",
                "ucp",
                "acp",
                "ap2"
              ]
            }
          }
        }
      },
      "EvidenceStep": {
        "type": "object",
        "required": [
          "action",
          "label"
        ],
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "fetch",
              "parse",
              "validate",
              "conclude"
            ]
          },
          "label": {
            "type": "string"
          },
          "request": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string"
              },
              "method": {
                "type": "string"
              },
              "headers": {
                "type": "object"
              }
            }
          },
          "response": {
            "type": "object",
            "properties": {
              "status": {
                "type": "integer"
              },
              "statusText": {
                "type": "string"
              },
              "headers": {
                "type": "object"
              },
              "bodyPreview": {
                "type": "string"
              }
            }
          },
          "finding": {
            "type": "object",
            "properties": {
              "outcome": {
                "type": "string",
                "enum": [
                  "positive",
                  "negative",
                  "neutral"
                ]
              },
              "summary": {
                "type": "string"
              }
            }
          }
        }
      },
      "CheckResult": {
        "type": "object",
        "required": [
          "status",
          "message",
          "messageRef",
          "evidence"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pass",
              "fail",
              "neutral",
              "unableToCheck"
            ]
          },
          "message": {
            "type": "string",
            "description": "Ergebnis auf Deutsch"
          },
          "messageRef": {
            "type": "object",
            "required": [
              "code"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "params": {
                "type": "object"
              }
            }
          },
          "details": {
            "type": "object"
          },
          "evidence": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvidenceStep"
            }
          },
          "durationMs": {
            "type": "integer"
          }
        }
      },
      "SiteError": {
        "type": "object",
        "properties": {
          "httpStatus": {
            "type": [
              "integer",
              "null"
            ]
          },
          "statusText": {
            "type": [
              "string",
              "null"
            ]
          },
          "bodyPreview": {
            "type": [
              "string",
              "null"
            ]
          },
          "retryAfter": {
            "type": [
              "string",
              "null"
            ]
          },
          "server": {
            "type": [
              "string",
              "null"
            ]
          },
          "cfRay": {
            "type": [
              "string",
              "null"
            ]
          },
          "errorClass": {
            "type": "string",
            "enum": [
              "blocked",
              "not_found",
              "rate_limited",
              "server_error",
              "client_error",
              "connection_error",
              "blocked_target"
            ]
          }
        }
      },
      "ScanResponse": {
        "type": "object",
        "required": [
          "url",
          "targetUrl",
          "scannedAt"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "Origin der gescannten Website"
          },
          "redirectedFrom": {
            "type": "string"
          },
          "targetUrl": {
            "type": "string"
          },
          "targetRedirectedFrom": {
            "type": "string"
          },
          "scannedAt": {
            "type": "string",
            "format": "date-time"
          },
          "level": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5
          },
          "levelName": {
            "type": "string"
          },
          "checks": {
            "type": "object",
            "description": "Ergebnisse je Kategorie: discoverability, contentAccessibility, botAccessControl, discovery, commerce",
            "additionalProperties": {
              "type": "object",
              "additionalProperties": {
                "$ref": "#/components/schemas/CheckResult"
              }
            }
          },
          "nextLevel": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "target": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "requirements": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "isCommerce": {
            "type": "boolean"
          },
          "commerceSignals": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "siteError": {
            "$ref": "#/components/schemas/SiteError"
          }
        }
      }
    }
  }
}