{
  "openapi": "3.0.3",
  "info": {
    "title": "Fudis API",
    "description": "Public and agentic REST API endpoints for Fudis restaurant discovery, menu access, and page markdown conversion. Versioning policy: API routes are path-versioned under /api/v1/. Deprecation warnings are signaled via standard Deprecation and Sunset headers.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://fudis.app",
      "description": "Production Server"
    }
  ],
  "paths": {
    "/api/markdown/{path}": {
      "get": {
        "summary": "Get markdown representation of any public Fudis page",
        "operationId": "getPageMarkdown",
        "description": "Converts any public HTML page on Fudis to clean, token-efficient Markdown suitable for AI agent context windows.",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Page route path (e.g. lima/pardos-chicken)"
          }
        ],
        "responses": {
          "200": {
            "description": "Markdown formatted content",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": { "type": "integer" },
                "description": "Request limit per minute"
              },
              "X-RateLimit-Remaining": {
                "schema": { "type": "integer" },
                "description": "Remaining requests in current window"
              },
              "X-RateLimit-Reset": {
                "schema": { "type": "integer" },
                "description": "Window reset epoch timestamp"
              }
            },
            "content": {
              "text/markdown": {}
            }
          },
          "404": {
            "description": "Page not found error response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "headers": {
              "Retry-After": {
                "schema": { "type": "integer" },
                "description": "Seconds to wait before retrying"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/backend/api/v1/restaurants": {
      "get": {
        "summary": "List restaurants with pagination and filters",
        "operationId": "listRestaurants",
        "description": "Retrieve paginated list of restaurants filtered by city, district, cuisine, price range, or search term.",
        "parameters": [
          {
            "name": "city",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "default": "lima" },
            "description": "City slug (e.g. lima)"
          },
          {
            "name": "district",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "District slug (e.g. miraflores)"
          },
          {
            "name": "price",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Price range filter ($, $$, $$$, $$$$)"
          },
          {
            "name": "skip",
            "in": "query",
            "required": false,
            "schema": { "type": "integer", "default": 0 },
            "description": "Number of records to skip"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": { "type": "integer", "default": 20 },
            "description": "Number of records to return"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of restaurants",
            "headers": {
              "X-RateLimit-Limit": { "schema": { "type": "integer" } },
              "X-RateLimit-Remaining": { "schema": { "type": "integer" } },
              "X-RateLimit-Reset": { "schema": { "type": "integer" } }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedRestaurantsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/backend/api/v1/cities": {
      "get": {
        "summary": "List active cities",
        "operationId": "listCities",
        "description": "Retrieve list of supported cities with their metadata and localized names.",
        "responses": {
          "200": {
            "description": "Array of city objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/City" }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "NOT_FOUND"
          },
          "message": {
            "type": "string",
            "example": "The requested resource was not found."
          },
          "hint": {
            "type": "string",
            "example": "Check /openapi.json for valid API endpoints."
          }
        },
        "required": ["code", "message"]
      },
      "City": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "slug": { "type": "string", "example": "lima" },
          "name": {
            "type": "object",
            "properties": {
              "es": { "type": "string", "example": "Lima" },
              "en": { "type": "string", "example": "Lima" }
            }
          },
          "country_code": { "type": "string", "example": "PE" }
        },
        "required": ["id", "slug", "name"]
      },
      "Restaurant": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "slug": { "type": "string", "example": "pardos-chicken" },
          "name": { "type": "string", "example": "Pardos Chicken" },
          "rating": { "type": "number", "example": 4.5 },
          "review_count": { "type": "integer", "example": 120 },
          "price_range": { "type": "string", "example": "$$" },
          "hero_image": { "type": "string", "nullable": true },
          "logo_url": { "type": "string", "nullable": true }
        },
        "required": ["id", "slug", "name"]
      },
      "PaginatedRestaurantsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Restaurant" }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "total": { "type": "integer", "example": 150 },
              "page": { "type": "integer", "example": 1 },
              "pageSize": { "type": "integer", "example": 20 },
              "totalPages": { "type": "integer", "example": 8 }
            },
            "required": ["total", "page", "pageSize", "totalPages"]
          }
        },
        "required": ["data", "pagination"]
      }
    }
  }
}
