{
  "openapi": "3.1.0",
  "info": {
    "title": "VettedHome Content API",
    "summary": "Read-only public index of VettedHome's UK home-services editorial pages.",
    "description": "Machine-readable access to the VettedHome content index: the editorial pages across the energy (solar, EV chargers, heat pumps, batteries, insulation, grants), property-fixes (spray foam removal, damp, cavity wall, drainage, cladding, knotweed) and trades tiers, each with its canonical URL and the primary sources cited on the page. This is a content and page index, not a priced dataset: indicative cost bands stay inside the page copy and are not exposed as machine figures. Source of truth is the on-site editorial content. Read-only, no authentication, no PII, CC BY 4.0. Also exposed as an MCP server at /mcp (see /.well-known/mcp.json). VettedHome is an independent comparison and introducer, not a lender or installer.",
    "version": "2026-06-12",
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "contact": {
      "name": "VettedHome",
      "url": "https://vettedhome.co.uk/api/"
    }
  },
  "servers": [
    { "url": "https://vettedhome.co.uk", "description": "Production" }
  ],
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://vettedhome.co.uk/api/"
  },
  "paths": {
    "/api/topics": {
      "get": {
        "operationId": "listTopics",
        "summary": "List VettedHome editorial pages",
        "description": "Returns the full content index, or a filtered subset when query params are supplied.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text match on name, heading and summary.",
            "schema": { "type": "string" }
          },
          {
            "name": "tier",
            "in": "query",
            "required": false,
            "description": "Filter by content tier.",
            "schema": {
              "type": "string",
              "enum": ["energy", "property-fixes", "trades", "trades-guide"]
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Filter by sub-group within a tier (for example solar, heatpump, damp, sprayfoam, electrical).",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of topics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schema_version": { "type": "string" },
                    "source": { "type": "string", "format": "uri" },
                    "license": { "type": "string", "format": "uri" },
                    "count": { "type": "integer" },
                    "topics": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Topic" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/topics/{slug}": {
      "get": {
        "operationId": "getTopic",
        "summary": "Get a single topic by slug",
        "description": "Slugs are unique within a tier but can repeat across tiers. Pass ?tier= to disambiguate; without it the first match wins (energy, then property-fixes, then trades, then guides).",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "example": "solar-panel-installation-cost"
          },
          {
            "name": "tier",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["energy", "property-fixes", "trades", "trades-guide"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The matching topic.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schema_version": { "type": "string" },
                    "source": { "type": "string", "format": "uri" },
                    "license": { "type": "string", "format": "uri" },
                    "topic": { "$ref": "#/components/schemas/Topic" }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No topic matches the slug.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/index-snapshot": {
      "get": {
        "operationId": "getIndexSnapshot",
        "summary": "Content coverage snapshot",
        "description": "Total editorial pages, the per-tier breakdown and the count of distinct primary-source bodies cited across the site. No priced figure is exposed because indicative cost bands stay inside the page copy.",
        "responses": {
          "200": {
            "description": "Coverage snapshot.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IndexSnapshot" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Source": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "url": { "type": "string", "format": "uri" }
        }
      },
      "Topic": {
        "type": "object",
        "properties": {
          "slug": { "type": "string" },
          "tier": {
            "type": "string",
            "enum": ["energy", "property-fixes", "trades", "trades-guide"]
          },
          "group": { "type": "string" },
          "name": { "type": "string" },
          "heading": { "type": "string" },
          "summary": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "sources": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Source" }
          }
        },
        "required": ["slug", "tier", "group", "name", "url"]
      },
      "IndexSnapshot": {
        "type": "object",
        "properties": {
          "schema_version": { "type": "string" },
          "as_of": { "type": "string", "format": "date" },
          "region": { "type": "string" },
          "topics_count": { "type": "integer" },
          "tiers": {
            "type": "object",
            "properties": {
              "energy": { "type": "integer" },
              "property-fixes": { "type": "integer" },
              "trades": { "type": "integer" },
              "trades-guide": { "type": "integer" }
            }
          },
          "distinct_primary_sources": { "type": "integer" },
          "note": { "type": "string" },
          "source": { "type": "string", "format": "uri" },
          "license": { "type": "string", "format": "uri" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "detail": { "type": "string" }
        }
      }
    }
  }
}
