{
  "openapi": "3.1.0",
  "info": {
    "title": "Property Investment Spain API",
    "description": "Public API for searching Spanish property listings, blog articles, and buying/selling/living guides. No authentication required.",
    "version": "1.0.0",
    "contact": {
      "name": "Property Investment Spain",
      "url": "https://www.propertyinvestmentspain.com"
    }
  },
  "servers": [
    {
      "url": "https://www.propertyinvestmentspain.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/knowledge": {
      "get": {
        "operationId": "getKnowledgeCatalog",
        "summary": "Knowledge catalog — start here",
        "description": "The single machine-first entry point for this business. Returns identity, services and pricing (free viewing trips, free lawyer consultation), coverage from Denia to Marbella, Spanish purchase-cost tax rates, an aggregated FAQ with source URLs, and a tool directory describing which endpoint answers which kind of user question. Call this first before any other endpoint.",
        "responses": {
          "200": {
            "description": "The full knowledge catalog",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Catalog with identity, coverage, services, pricing, policies, serviceAreas, tools, faq, and machineResources sections"
                }
              }
            }
          }
        }
      }
    },
    "/api/properties": {
      "get": {
        "operationId": "listProperties",
        "summary": "List all properties for sale in Spain",
        "description": "Returns an array of property listings on the Costa Blanca and Costa Calida. Results are cached for 5 minutes.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of properties to return",
            "schema": {
              "type": "integer",
              "default": 2000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of property objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Property"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/properties/{id}": {
      "get": {
        "operationId": "getProperty",
        "summary": "Get a single property by ID",
        "description": "Returns detailed information about a specific property, including similar property suggestions.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The property ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Property details with similar properties",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "property": {
                      "$ref": "#/components/schemas/Property"
                    },
                    "similarProperties": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Property"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Property not found"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/blog": {
      "get": {
        "operationId": "listBlogArticles",
        "summary": "List blog articles about property investment in Spain",
        "description": "Returns blog articles filtered by language, category, place, and region. Articles cover buying, selling, and living in Spain.",
        "parameters": [
          {
            "name": "lang",
            "in": "query",
            "description": "Language code for article content",
            "schema": {
              "type": "string",
              "enum": ["en", "es", "de", "fr", "nl", "sv", "no", "da", "ru", "pl", "it"],
              "default": "en"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by article category",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "place",
            "in": "query",
            "description": "Filter by town/place name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "region",
            "in": "query",
            "description": "Filter by region name (e.g. Costa Blanca North, Costa Blanca South, Costa Calida)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of articles to return",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of blog articles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "articles": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogArticle"
                      }
                    }
                  },
                  "required": ["success", "total", "articles"]
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": false
                    },
                    "error": {
                      "type": "string"
                    },
                    "articles": {
                      "type": "array",
                      "items": {}
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/guides": {
      "get": {
        "operationId": "listGuides",
        "summary": "List buying, selling, and living guides for Spain",
        "description": "Returns guides filtered by language and subcategory. Guides provide step-by-step information about the Spanish property process.",
        "parameters": [
          {
            "name": "lang",
            "in": "query",
            "description": "Language code for guide content",
            "schema": {
              "type": "string",
              "enum": ["en", "es", "de", "fr", "nl", "sv", "no", "da", "ru", "pl", "it"],
              "default": "en"
            }
          },
          {
            "name": "subcategory",
            "in": "query",
            "description": "Filter by guide subcategory",
            "schema": {
              "type": "string",
              "enum": ["buying", "selling", "living"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of guides",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "guides": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Guide"
                      }
                    }
                  },
                  "required": ["success", "total", "guides"]
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": false
                    },
                    "error": {
                      "type": "string"
                    },
                    "guides": {
                      "type": "array",
                      "items": {}
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/calculators": {
      "get": {
        "operationId": "listCalculators",
        "summary": "Directory of the property cost calculator APIs",
        "description": "Lists the five compute endpoints with their parameters and example URLs. Use these to answer 'what does it cost to buy, own, sell, finance, or rent out a property in Spain' with actual numbers.",
        "responses": {
          "200": {
            "description": "Directory of calculator endpoints",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      }
    },
    "/api/calculators/purchase-costs": {
      "get": {
        "operationId": "calculatePurchaseCosts",
        "summary": "Total cost of buying a property in Spain",
        "description": "Computes the all-in purchase cost: transfer tax (ITP 10% Valencia / 8% Murcia / 7% Andalusia) or IVA 10% + AJD 1.5% for new builds, lawyer (1% + VAT), notary, and land registry, plus a financing estimate at 70% loan-to-value.",
        "parameters": [
          { "name": "price", "in": "query", "required": true, "description": "Purchase price in EUR", "schema": { "type": "number", "minimum": 1 } },
          { "name": "region", "in": "query", "description": "Tax region", "schema": { "type": "string", "enum": ["valencia", "murcia", "andalusia"], "default": "valencia" } },
          { "name": "newBuild", "in": "query", "description": "New build pays IVA + AJD instead of ITP", "schema": { "type": "boolean", "default": false } }
        ],
        "responses": {
          "200": { "description": "Cost breakdown with inputs, results, assumptions, and disclaimer", "content": { "application/json": { "schema": { "type": "object" } } } },
          "400": { "description": "Missing or invalid parameter" }
        }
      }
    },
    "/api/calculators/annual-costs": {
      "get": {
        "operationId": "calculateAnnualCosts",
        "summary": "Annual running costs of owning a property in Spain",
        "description": "Estimates yearly IBI property tax, community fees, insurance, utilities, and maintenance for a Spanish property.",
        "parameters": [
          { "name": "propertyType", "in": "query", "schema": { "type": "string", "enum": ["apartment", "townhouse", "villa"], "default": "apartment" } },
          { "name": "bedrooms", "in": "query", "schema": { "type": "integer", "minimum": 0, "maximum": 10, "default": 2 } },
          { "name": "pool", "in": "query", "description": "Private pool maintenance", "schema": { "type": "boolean", "default": false } },
          { "name": "urbanisation", "in": "query", "description": "Community fees apply", "schema": { "type": "boolean", "default": true } }
        ],
        "responses": {
          "200": { "description": "Annual cost breakdown", "content": { "application/json": { "schema": { "type": "object" } } } },
          "400": { "description": "Invalid parameter" }
        }
      }
    },
    "/api/calculators/selling-costs": {
      "get": {
        "operationId": "calculateSellingCosts",
        "summary": "Cost of selling a property in Spain (non-resident)",
        "description": "Computes agent fee, legal fees, non-resident capital gains tax (19% flat), and net proceeds from a sale.",
        "parameters": [
          { "name": "salePrice", "in": "query", "required": true, "schema": { "type": "number", "minimum": 1 } },
          { "name": "purchasePrice", "in": "query", "required": true, "description": "Original purchase price", "schema": { "type": "number", "minimum": 1 } },
          { "name": "improvements", "in": "query", "description": "Documented improvement costs", "schema": { "type": "number", "default": 0 } },
          { "name": "agentFeePercent", "in": "query", "schema": { "type": "number", "minimum": 0, "maximum": 15, "default": 5 } },
          { "name": "outstandingMortgage", "in": "query", "schema": { "type": "number", "default": 0 } }
        ],
        "responses": {
          "200": { "description": "Selling cost breakdown and net proceeds", "content": { "application/json": { "schema": { "type": "object" } } } },
          "400": { "description": "Missing or invalid parameter" }
        }
      }
    },
    "/api/calculators/mortgage": {
      "get": {
        "operationId": "calculateMortgage",
        "summary": "Spanish mortgage payment estimate",
        "description": "Computes monthly payment, total interest, deposit, and total equity needed (deposit + ~12% taxes and fees).",
        "parameters": [
          { "name": "propertyPrice", "in": "query", "required": true, "schema": { "type": "number", "minimum": 1 } },
          { "name": "loanPercentage", "in": "query", "schema": { "type": "number", "minimum": 1, "maximum": 100, "default": 70 } },
          { "name": "interestRate", "in": "query", "description": "Annual rate in percent", "schema": { "type": "number", "minimum": 0, "maximum": 20, "default": 3.5 } },
          { "name": "years", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 40, "default": 25 } }
        ],
        "responses": {
          "200": { "description": "Mortgage breakdown", "content": { "application/json": { "schema": { "type": "object" } } } },
          "400": { "description": "Missing or invalid parameter" }
        }
      }
    },
    "/api/calculators/rental-income": {
      "get": {
        "operationId": "calculateRentalIncome",
        "summary": "Holiday rental income estimate (Costa Blanca baseline)",
        "description": "Estimates gross and net annual holiday-rental income by property type, location quality, and rental strategy, including management, platform, and tax expenses.",
        "parameters": [
          { "name": "propertyType", "in": "query", "schema": { "type": "string", "enum": ["apartment-1bed", "apartment-2bed", "apartment-3bed", "townhouse", "villa-small", "villa-large"], "default": "apartment-2bed" } },
          { "name": "location", "in": "query", "schema": { "type": "string", "enum": ["prime", "popular", "standard", "rural"], "default": "popular" } },
          { "name": "strategy", "in": "query", "schema": { "type": "string", "enum": ["high-only", "high-shoulder", "full-year"], "default": "high-shoulder" } }
        ],
        "responses": {
          "200": { "description": "Rental income breakdown", "content": { "application/json": { "schema": { "type": "object" } } } },
          "400": { "description": "Invalid parameter" }
        }
      }
    },
    "/api/leads": {
      "post": {
        "operationId": "submitLead",
        "summary": "Submit a lead: request a viewing trip, video viewing, or lawyer consultation",
        "description": "Submits a contact request to Property Investment Spain on behalf of a user. Use this when a user explicitly asks to get in touch, book a property viewing trip, arrange a video viewing, or request a lawyer consultation. Only submit with the user's consent and with the user's real contact details. A local adviser replies by email, typically within one business day.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Lead accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — a required field is missing or invalid"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "LeadRequest": {
        "type": "object",
        "required": ["name", "email", "message"],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "The user's full name"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "The user's email address — replies are sent here"
          },
          "message": {
            "type": "string",
            "maxLength": 5000,
            "description": "What the user is looking for, in their own words: budget, area, timeline, property preferences, questions"
          },
          "interest": {
            "type": "string",
            "enum": ["viewing-trip", "video-viewing", "lawyer-consultation", "property-inquiry", "general"],
            "default": "general",
            "description": "What the user wants to arrange"
          },
          "preferredLanguage": {
            "type": "string",
            "enum": ["en", "es", "de", "fr", "nl", "sv", "no", "da", "ru", "pl", "it"],
            "description": "The language the user prefers to be contacted in"
          },
          "phone": {
            "type": "string",
            "maxLength": 50,
            "description": "The user's phone number, optional"
          },
          "contactMethod": {
            "type": "string",
            "enum": ["email", "whatsapp", "phone"],
            "default": "email",
            "description": "How the user prefers to be contacted"
          },
          "propertyRef": {
            "type": "string",
            "maxLength": 100,
            "description": "Property ID from /api/properties, when the lead concerns a specific listing"
          },
          "propertyUrl": {
            "type": "string",
            "maxLength": 500,
            "description": "URL of the property or page the lead concerns, when applicable"
          },
          "source": {
            "type": "string",
            "maxLength": 200,
            "description": "Name of the assistant or platform submitting the lead, e.g. \"ChatGPT\" or \"Claude\""
          }
        }
      },
      "Property": {
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique property identifier"
          },
          "title": {
            "type": "string",
            "description": "Property listing title"
          },
          "type": {
            "type": "string",
            "enum": ["Villa", "Apartment", "House", "Plot"],
            "description": "Property type"
          },
          "town": {
            "type": "string",
            "description": "Town where the property is located"
          },
          "urbanisation": {
            "type": "string",
            "description": "Urbanisation/development name"
          },
          "province": {
            "type": "string",
            "description": "Province (e.g. Alicante, Murcia)"
          },
          "price": {
            "type": "number",
            "description": "Listing price in euros"
          },
          "bedrooms": {
            "type": "integer",
            "description": "Number of bedrooms"
          },
          "bathrooms": {
            "type": "integer",
            "description": "Number of bathrooms"
          },
          "size_m2": {
            "type": "number",
            "description": "Interior size in square meters"
          },
          "size": {
            "type": "number",
            "description": "Interior size in square meters (alias)"
          },
          "plot_m2": {
            "type": "number",
            "description": "Plot size in square meters"
          },
          "new_build": {
            "type": "boolean",
            "description": "Whether the property is a new build"
          },
          "featured": {
            "type": "boolean",
            "description": "Whether the property is featured"
          },
          "pool": {
            "type": "boolean",
            "description": "Whether the property has a pool"
          },
          "views": {
            "type": "string",
            "description": "View type (e.g. Sea view, Mountain view)"
          },
          "orientation": {
            "type": "string",
            "description": "Property orientation"
          },
          "description": {
            "type": "string",
            "description": "Full property description"
          },
          "features": {
            "type": "array",
            "items": { "type": "string" },
            "description": "List of property features"
          },
          "images": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Array of image URLs"
          },
          "lat": {
            "type": "number",
            "description": "Latitude coordinate"
          },
          "lng": {
            "type": "number",
            "description": "Longitude coordinate"
          },
          "ref": {
            "type": "string",
            "description": "External reference number"
          },
          "listed_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO date when the property was listed"
          }
        }
      },
      "BlogArticle": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique article identifier"
          },
          "slug": {
            "type": "string",
            "description": "URL slug for the article"
          },
          "title": {
            "type": "string",
            "description": "Article title"
          },
          "description": {
            "type": "string",
            "description": "Short article description"
          },
          "summary": {
            "type": "string",
            "description": "Article summary"
          },
          "image": {
            "type": "string",
            "description": "Featured image URL"
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "Publication date (YYYY-MM-DD)"
          },
          "author": {
            "type": "string",
            "description": "Article author name"
          },
          "readTime": {
            "type": "string",
            "description": "Estimated read time"
          },
          "category": {
            "type": "string",
            "description": "Article category"
          },
          "regions": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Regions covered by the article"
          },
          "places": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Places/towns mentioned in the article"
          },
          "tags": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Topic tags"
          },
          "availableLanguages": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Language codes this article is available in"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Full URL to the article"
          }
        },
        "required": ["id", "slug", "title", "url"]
      },
      "Guide": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique guide identifier"
          },
          "slug": {
            "type": "string",
            "description": "URL slug for the guide"
          },
          "title": {
            "type": "string",
            "description": "Guide title"
          },
          "description": {
            "type": "string",
            "description": "Guide description"
          },
          "linkTitle": {
            "type": "string",
            "description": "Short title for links"
          },
          "linkDescription": {
            "type": "string",
            "description": "Short description for links"
          },
          "subcategory": {
            "type": "string",
            "enum": ["buying", "selling", "living"],
            "description": "Guide subcategory"
          },
          "image": {
            "type": "string",
            "description": "Featured image URL"
          },
          "weight": {
            "type": "integer",
            "description": "Sort order weight"
          },
          "availableLanguages": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Language codes this guide is available in"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Full URL to the guide"
          }
        },
        "required": ["id", "slug", "title", "subcategory", "url"]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          }
        }
      }
    }
  }
}
