{
  "openapi": "3.0.3",
  "info": {
    "title": "HSD Optical Public API",
    "description": "Public, read-only access to HSD Optical's content: pages, posts, media, content types and site search. No authentication is required for the endpoints documented here. Write endpoints of the WordPress REST API require authentication and are intentionally not part of this public contract. For a human-readable site overview, see /llms.txt.\n\nRate limits: the public read-only API allows 1,200 requests per hour per client. Responses include RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers.\n\nVersioning and deprecation: the WordPress REST API uses URL versioning (the wp/v2 namespace). This public contract tracks the current wp/v2 surface; no endpoints are currently deprecated. If an endpoint is deprecated in the future, a Sunset header will be included in responses and the deprecated route will remain available for at least 90 days.",
    "version": "1.0.0",
    "contact": {
      "name": "HSD Optical",
      "email": "rfq@hsdoptical.com",
      "url": "https://hsdoptical.com/contact/"
    },
    "license": {
      "name": "Proprietary content — public read-only access granted",
      "url": "https://hsdoptical.com/privacy-policy/"
    }
  },
  "servers": [
    {
      "url": "https://hsdoptical.com",
      "description": "Production server"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Content",
      "description": "Read-only content endpoints (pages, posts, media, types)"
    },
    {
      "name": "Search",
      "description": "Site-wide search across content types"
    }
  ],
  "paths": {
    "/wp-json": {
      "get": {
        "tags": ["Content"],
        "operationId": "getApiIndex",
        "summary": "WordPress REST API index",
        "description": "Lists every registered REST route and namespace on the site, including namespaces outside this contract. Use this to discover available routes.",
        "responses": {
          "200": {
            "description": "API index with namespaces and route map",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "example": "HSD Optical"
                    },
                    "namespaces": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "routes": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/wp-json/wp/v2/pages": {
      "get": {
        "tags": ["Content"],
        "operationId": "listPages",
        "summary": "List published pages",
        "description": "Returns published pages (including product, solution and company pages) in the site's WordPress content. Read-only, no authentication required.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Context"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "$ref": "#/components/parameters/OrderBy"
          },
          {
            "$ref": "#/components/parameters/Order"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of page objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ContentItem"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/wp-json/wp/v2/pages/{id}": {
      "get": {
        "tags": ["Content"],
        "operationId": "getPage",
        "summary": "Get a single page by ID",
        "description": "Returns one published page by its WordPress post ID. Use the search endpoint or the page list to resolve an ID from a URL.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/Context"
          }
        ],
        "responses": {
          "200": {
            "description": "Page object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentItem"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/wp-json/wp/v2/posts": {
      "get": {
        "tags": ["Content"],
        "operationId": "listPosts",
        "summary": "List published blog posts",
        "description": "Returns published blog posts from the HSD Optical blog. Read-only, no authentication required.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Context"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/Search"
          },
          {
            "$ref": "#/components/parameters/OrderBy"
          },
          {
            "$ref": "#/components/parameters/Order"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of post objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ContentItem"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/wp-json/wp/v2/media": {
      "get": {
        "tags": ["Content"],
        "operationId": "listMedia",
        "summary": "List media items",
        "description": "Returns media library items (images, PDFs and other uploads). Useful for resolving featured images and downloadable files.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/Search"
          }
        ],
        "responses": {
          "200": {
            "description": "Array of media objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MediaItem"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/wp-json/wp/v2/types": {
      "get": {
        "tags": ["Content"],
        "operationId": "listContentTypes",
        "summary": "List registered content types",
        "description": "Returns the registered post types (page, post, attachment, etc.) with their labels and REST base routes.",
        "responses": {
          "200": {
            "description": "Map of content type slug to definition",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "rest_base": {
                        "type": "string"
                      },
                      "slug": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/wp-json/wp/v2/search": {
      "get": {
        "tags": ["Search"],
        "operationId": "searchSite",
        "summary": "Search site content",
        "description": "Full-text search across pages and posts. Returns matching content with type, title and canonical URL. The recommended way for agents to find relevant HSD Optical content by topic.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": true,
            "description": "Search term (for example: rod lens, centration, coating blank).",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "rod lens"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Restrict results to one content type.",
            "schema": {
              "type": "string",
              "enum": ["post", "page"],
              "default": "any"
            }
          },
          {
            "name": "subtype",
            "in": "query",
            "description": "Restrict results to a specific post type.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of search results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SearchResult"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/ErrorResponse"
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    }
  },
    "components": {
    "parameters": {
      "Context": {
        "name": "context",
        "in": "query",
        "description": "Scope under which the request is made; determines fields present in the response.",
        "schema": {
          "type": "string",
          "enum": ["view", "embed", "edit"],
          "default": "view"
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "description": "Current page of the collection.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "description": "Maximum number of items to be returned in the result set.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 10
        }
      },
      "Search": {
        "name": "search",
        "in": "query",
        "description": "Limit results to those matching a search term.",
        "schema": {
          "type": "string"
        }
      },
      "OrderBy": {
        "name": "orderby",
        "in": "query",
        "description": "Sort collection by object attribute.",
        "schema": {
          "type": "string",
          "enum": ["date", "id", "include", "modified", "parent", "relevance", "slug", "title"],
          "default": "date"
        }
      },
      "Order": {
        "name": "order",
        "in": "query",
        "description": "Order sort attribute ascending or descending.",
        "schema": {
          "type": "string",
          "enum": ["asc", "desc"],
          "default": "desc"
        }
      },
      "Id": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "WordPress content ID.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "responses": {
      "ErrorResponse": {
        "description": "Structured JSON error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          },
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "WordPress REST error object with a stable code and a resolution hint.",
        "required": ["code", "message"],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "Reference to the error type or API documentation.",
            "example": "https://hsdoptical.com/openapi.json#errors"
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code.",
            "example": "rest_no_route"
          },
          "message": {
            "type": "string",
            "description": "Human-readable error message.",
            "example": "No route was found matching the URL and request method."
          },
          "resolution": {
            "type": "string",
            "description": "Actionable next step for the caller.",
            "example": "List available routes at /wp-json/ or see /openapi.json."
          },
          "data": {
            "type": "object",
            "description": "Additional error context, including the HTTP status.",
            "properties": {
              "status": {
                "type": "integer",
                "example": 404
              }
            }
          }
        }
      },
      "ContentItem": {
        "type": "object",
        "description": "A page or post object. Rendering fields (title, content, excerpt) are only present for view/embed contexts.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "modified": {
            "type": "string",
            "format": "date-time"
          },
          "slug": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "example": "publish"
          },
          "type": {
            "type": "string",
            "example": "page"
          },
          "link": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "object",
            "properties": {
              "rendered": {
                "type": "string"
              }
            }
          },
          "content": {
            "type": "object",
            "properties": {
              "rendered": {
                "type": "string",
                "description": "Rendered HTML content."
              }
            }
          },
          "excerpt": {
            "type": "object",
            "properties": {
              "rendered": {
                "type": "string"
              }
            }
          },
          "featured_media": {
            "type": "integer"
          }
        }
      },
      "MediaItem": {
        "type": "object",
        "description": "A media library item.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "slug": {
            "type": "string"
          },
          "source_url": {
            "type": "string",
            "format": "uri",
            "description": "Full URL to the media file."
          },
          "media_type": {
            "type": "string",
            "example": "image"
          },
          "mime_type": {
            "type": "string",
            "example": "image/webp"
          },
          "caption": {
            "type": "object",
            "properties": {
              "rendered": {
                "type": "string"
              }
            }
          },
          "alt_text": {
            "type": "string"
          }
        }
      },
      "SearchResult": {
        "type": "object",
        "description": "A site-wide search result.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical URL of the matching content."
          },
          "type": {
            "type": "string",
            "example": "post"
          },
          "subtype": {
            "type": "string",
            "example": "page"
          }
        }
      }
    }
  }
}
