{
  "openapi": "3.1.0",
  "info": {
    "title": "kosename.me Public API",
    "version": "1.0.0",
    "summary": "Read-only API über die kuratierte Wissensbasis deutscher Kosenamen.",
    "description": "Public REST API for the curated German pet-names knowledge base at kosename.me. All endpoints are read-only, anonymous and rate-limited at 60 req/min/IP. Responses are JSON; ETag + Cache-Control supported. Content licensed under CC BY 4.0 — attribution to kosename.me + entry URL required.",
    "contact": {
      "name": "kosename.me — AI partnerships",
      "email": "ai@kosename.me",
      "url": "https://www.kosename.me/developers"
    },
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "termsOfService": "https://www.kosename.me/.well-known/ai.txt"
  },
  "servers": [
    {
      "url": "https://www.kosename.me",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Developer guide",
    "url": "https://www.kosename.me/developers"
  },
  "tags": [
    {
      "name": "names",
      "description": "Kuratierte Kosenamen-Einträge."
    },
    {
      "name": "categories",
      "description": "Kategorien-Taxonomie."
    },
    {
      "name": "search",
      "description": "Volltextsuche."
    },
    {
      "name": "nlweb",
      "description": "Natural-language /ask endpoint."
    },
    {
      "name": "meta",
      "description": "Discovery & status."
    }
  ],
  "paths": {
    "/api/names": {
      "get": {
        "tags": [
          "names"
        ],
        "operationId": "listNames",
        "summary": "List all curated names",
        "description": "Returns the full curated list of pet-name entries. Optional filtering by category or mood.",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by category slug (e.g. \"partner\", \"tiere\", \"englisch\").",
            "example": "partner"
          },
          {
            "name": "mood",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by mood/vibe tag.",
            "example": "süß"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 200
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NameList"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Soft per-IP minute budget."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/names/{slug}": {
      "get": {
        "tags": [
          "names"
        ],
        "operationId": "getName",
        "summary": "Get a single name by slug",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Slug, e.g. \"schatzi\" or \"baerchen\".",
            "example": "schatzi"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Name"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/categories": {
      "get": {
        "tags": [
          "categories"
        ],
        "operationId": "listCategories",
        "summary": "List all categories",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryList"
                }
              }
            }
          }
        }
      }
    },
    "/api/categories/{slug}": {
      "get": {
        "tags": [
          "categories"
        ],
        "operationId": "getCategory",
        "summary": "Get a single category with its names",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "partner"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Category"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/search": {
      "get": {
        "tags": [
          "search"
        ],
        "operationId": "searchNames",
        "summary": "Full-text search across names",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            },
            "description": "Query string. Searches title, meaning, variants, keywords.",
            "example": "maus"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/ask": {
      "post": {
        "tags": [
          "nlweb"
        ],
        "operationId": "nlwebAsk",
        "summary": "Microsoft NLWeb /ask endpoint — natural-language query",
        "description": "Accepts a free-form German or English question about pet names. Returns NLWeb-formatted JSON (with `_meta` and `result` arrays). Supports SSE streaming via `prefer.streaming: true`.",
        "parameters": [
          {
            "name": "prefer.streaming",
            "in": "header",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Opt into SSE streaming."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AskRequest"
              },
              "example": {
                "query": "Was bedeutet Schatzi?"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AskResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "NLWeb event stream (start, result, complete)."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": [
          "meta"
        ],
        "operationId": "mcpInvoke",
        "summary": "MCP Streamable HTTP transport",
        "description": "Model Context Protocol endpoint. Send JSON-RPC 2.0 requests; responses are JSON-RPC, optionally streamed as SSE. See /.well-known/mcp/server-card.json for tool list.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": [
          "meta"
        ],
        "operationId": "getStatus",
        "summary": "Service status",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Name": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "meaning"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "pronunciation": {
            "type": "string"
          },
          "ipa": {
            "type": "string"
          },
          "meaning": {
            "type": "string",
            "description": "One- to two-sentence canonical definition."
          },
          "origin": {
            "type": "string",
            "description": "Etymology / cultural origin (markdown)."
          },
          "usage": {
            "type": "string",
            "description": "Usage guidance (markdown)."
          },
          "examples": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "4 example sentences."
          },
          "variants": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "moods": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "faq": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "question": {
                  "type": "string"
                },
                "answer": {
                  "type": "string"
                }
              }
            }
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "datePublished": {
            "type": "string",
            "format": "date"
          },
          "lastReviewed": {
            "type": "string",
            "format": "date"
          },
          "license": {
            "type": "string",
            "example": "CC BY 4.0"
          }
        }
      },
      "NameSummary": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "meaning": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "NameList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NameSummary"
            }
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "license": {
            "type": "string"
          },
          "nextUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true
          }
        }
      },
      "Category": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "emoji": {
            "type": "string"
          },
          "moods": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "names": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NameSummary"
            }
          }
        }
      },
      "CategoryList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Category"
            }
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "SearchResult": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "meaning": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "score": {
            "type": "number"
          }
        }
      },
      "SearchResults": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchResult"
            }
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "AskRequest": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "minLength": 2
          },
          "site": {
            "type": "string",
            "default": "kosename.me"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "default": 5
          }
        }
      },
      "AskResponse": {
        "type": "object",
        "properties": {
          "_meta": {
            "type": "object",
            "properties": {
              "response_type": {
                "type": "string",
                "example": "nlweb.result"
              },
              "version": {
                "type": "string",
                "example": "0.4"
              },
              "site": {
                "type": "string",
                "example": "kosename.me"
              }
            }
          },
          "result": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "@type": {
                  "type": "string",
                  "example": "Article"
                },
                "name": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "description": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "method": {
            "type": "string",
            "example": "tools/list"
          },
          "params": {
            "type": "object"
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "result": {},
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {}
            }
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded",
              "down"
            ]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "string"
          },
          "names": {
            "type": "integer"
          },
          "categories": {
            "type": "integer"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "not_found"
              },
              "message": {
                "type": "string"
              },
              "hint": {
                "type": "string"
              },
              "docs": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "Not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Bad request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limited",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Limit": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            }
          }
        }
      }
    }
  }
}