{
  "openapi": "3.1.0",
  "info": {
    "title": "Kvartiry-Phuket open data API",
    "version": "1.0.0",
    "summary": "Гайды, районы, цены предложения и официальные оценочные ставки по Пхукету",
    "description": "Статичные JSON-файлы и MCP-сервер Kvartiry-Phuket для ИИ-ассистентов, агрегаторов и разработчиков. Ключ не нужен, CORS разрешён. Каждый документ содержит объект attribution; при использовании указывайте source_url. Условия: https://kvartiry-phuket.com/otkrytye-dannye/#perepechatka",
    "contact": {
      "name": "Kvartiry-Phuket",
      "email": "hello@kvartiry-phuket.com",
      "url": "https://kvartiry-phuket.com/otkrytye-dannye/"
    },
    "license": {
      "name": "Mixed terms, see the reuse policy",
      "url": "https://kvartiry-phuket.com/otkrytye-dannye/#perepechatka"
    }
  },
  "externalDocs": {
    "description": "Документация и условия перепечатки",
    "url": "https://kvartiry-phuket.com/otkrytye-dannye/"
  },
  "servers": [
    {
      "url": "https://kvartiry-phuket.com"
    }
  ],
  "paths": {
    "/api/v1/index.json": {
      "get": {
        "operationId": "getIndex",
        "summary": "Каталог эндпоинтов, правила атрибуции, ссылки на OpenAPI и MCP",
        "responses": {
          "200": {
            "description": "Каталог API",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/articles.json": {
      "get": {
        "operationId": "listArticles",
        "summary": "Индексируемые гайды (только URL из sitemap.xml, без карантина)",
        "responses": {
          "200": {
            "description": "Список гайдов",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArticleList"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/articles/{slug}.json": {
      "get": {
        "operationId": "getArticle",
        "summary": "Гайд: вступление, разделы H2, вопросы FAQ, атрибуция",
        "parameters": [
          {
            "$ref": "#/components/parameters/Slug"
          }
        ],
        "responses": {
          "200": {
            "description": "Гайд",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Article"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/districts.json": {
      "get": {
        "operationId": "listDistricts",
        "summary": "Районы Пхукета из раздела /raions/",
        "responses": {
          "200": {
            "description": "Районы",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/prices.json": {
      "get": {
        "operationId": "getAskingPrices",
        "summary": "Датированный срез цен предложения (asking prices), CC BY 4.0",
        "description": "Цены объявлений, не цены сделок. Методика и ограничения — в полях method и limitations_ru.",
        "responses": {
          "200": {
            "description": "Срез цен",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/condo-assessment.json": {
      "get": {
        "operationId": "getCondoAssessment",
        "summary": "Официальные оценочные ставки по кондоминиумам (не рыночная цена)",
        "responses": {
          "200": {
            "description": "Оценочные ставки",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/openapi.json": {
      "get": {
        "operationId": "getOpenApi",
        "summary": "Этот документ",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/blog/{slug}/index.md": {
      "get": {
        "operationId": "getArticleMarkdown",
        "summary": "Markdown-версия гайда (noindex, Link rel=canonical на HTML)",
        "parameters": [
          {
            "$ref": "#/components/parameters/Slug"
          }
        ],
        "responses": {
          "200": {
            "description": "Markdown с YAML front matter и строкой атрибуции",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "<HTML URL>; rel=\"alternate\"; type=\"text/html\""
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Гайд не найден"
          }
        }
      }
    },
    "/.well-known/mcp.json": {
      "get": {
        "operationId": "getMcpDiscovery",
        "summary": "Описание MCP-сервера для автоматического обнаружения",
        "responses": {
          "200": {
            "description": "MCP discovery",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "const": "*"
                }
              },
              "X-Robots-Tag": {
                "schema": {
                  "type": "string",
                  "const": "noindex"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "MCP-сервер (Streamable HTTP, без состояния, ответы JSON, только чтение)",
        "description": "JSON-RPC 2.0: initialize, notifications/initialized, ping, tools/list, tools/call. Поддерживаемые версии протокола: 2025-06-18, 2025-03-26. Инструменты: search_guides, get_guide, list_districts, get_district, get_asking_prices, get_condo_assessment. Тело запроса — не более 64 KiB.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/JsonRpcMessage"
                  },
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/JsonRpcMessage"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC ответ (или массив ответов для пакета)",
            "content": {
              "application/json": {
                "schema": {
                  "type": [
                    "object",
                    "array"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Уведомление принято, тела нет"
          },
          "400": {
            "description": "Ошибка разбора (-32700) или неверный запрос (-32600)"
          },
          "413": {
            "description": "Тело запроса больше 64 KiB"
          }
        }
      },
      "get": {
        "operationId": "mcpGet",
        "summary": "SSE-поток не поддерживается",
        "responses": {
          "405": {
            "description": "Method Not Allowed (Allow: POST)"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Slug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]{0,119}$"
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "Ресурс не найден",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "string"
                },
                "docs": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Attribution": {
        "type": "object",
        "required": [
          "source",
          "source_url",
          "license",
          "required_credit_html",
          "reuse_policy"
        ],
        "properties": {
          "source": {
            "type": "string"
          },
          "source_url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "license": {
            "type": "string"
          },
          "license_url": {
            "type": "string",
            "format": "uri"
          },
          "terms_ru": {
            "type": "string"
          },
          "required_credit_html": {
            "type": "string"
          },
          "required_credit_text": {
            "type": "string"
          },
          "citation_request": {
            "type": "string"
          },
          "reuse_policy": {
            "type": "string",
            "format": "uri"
          },
          "photos": {
            "type": "string"
          },
          "photos_en": {
            "type": "string"
          }
        }
      },
      "Document": {
        "type": "object",
        "required": [
          "attribution"
        ],
        "properties": {
          "attribution": {
            "$ref": "#/components/schemas/Attribution"
          }
        }
      },
      "ArticleSummary": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "date_published": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "date_modified": {
            "type": "string",
            "format": "date"
          },
          "markdown_url": {
            "type": "string",
            "format": "uri"
          },
          "api_url": {
            "type": "string",
            "format": "uri"
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "faq_questions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ArticleList": {
        "type": "object",
        "required": [
          "articles",
          "attribution"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "articles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ArticleSummary"
            }
          },
          "attribution": {
            "$ref": "#/components/schemas/Attribution"
          }
        }
      },
      "Article": {
        "type": "object",
        "required": [
          "slug",
          "url",
          "title",
          "outline",
          "attribution"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "h1": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "date_modified": {
            "type": "string",
            "format": "date"
          },
          "markdown_url": {
            "type": "string",
            "format": "uri"
          },
          "intro": {
            "type": "string"
          },
          "outline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "faq_questions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "attribution": {
            "$ref": "#/components/schemas/Attribution"
          }
        }
      },
      "JsonRpcMessage": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer"
            ]
          },
          "method": {
            "type": "string"
          },
          "params": {
            "type": "object"
          }
        }
      }
    }
  },
  "x-attribution": {
    "source": "Kvartiry-Phuket",
    "source_url": "https://kvartiry-phuket.com/otkrytye-dannye/",
    "title": "Открытые данные Kvartiry-Phuket",
    "license": "Mixed: editorial content — quoting/reprint only with an active link; /ceny/ aggregates — CC BY 4.0; official Treasury data — source terms; photos excluded",
    "license_url": "https://kvartiry-phuket.com/otkrytye-dannye/#perepechatka",
    "terms_ru": "Цитирование и перепечатка — только с активной ссылкой на страницу-источник. Это не лицензия Creative Commons.",
    "required_credit_html": "Источник: <a href=\"https://kvartiry-phuket.com/otkrytye-dannye/\">Открытые данные Kvartiry-Phuket — Kvartiry-Phuket</a>",
    "required_credit_text": "Источник: Открытые данные Kvartiry-Phuket — Kvartiry-Phuket, https://kvartiry-phuket.com/otkrytye-dannye/",
    "citation_request": "При использовании укажите источник: https://kvartiry-phuket.com/otkrytye-dannye/",
    "reuse_policy": "https://kvartiry-phuket.com/otkrytye-dannye/#perepechatka",
    "photos": "Фотографии не входят в разрешение на повторное использование: это работы третьих лиц с собственными лицензиями правообладателей.",
    "photos_en": "Photos are excluded from this permission: they are third-party works under their own licences."
  },
  "x-reuse-policy": "https://kvartiry-phuket.com/otkrytye-dannye/#perepechatka",
  "x-mcp": {
    "endpoint": "https://kvartiry-phuket.com/mcp",
    "transport": "streamable-http",
    "protocol_versions": [
      "2025-06-18",
      "2025-03-26"
    ],
    "tools": [
      "search_guides",
      "get_guide",
      "list_districts",
      "get_district",
      "get_asking_prices",
      "get_condo_assessment"
    ]
  }
}
