{
  "openapi": "3.1.0",
  "info": {
    "title": "Homepage public API",
    "version": "1.0.0",
    "description": "Homepage lets New Zealanders sell their own home. Each property gets its own standalone website at its own web address, plus a matching set of marketing materials: flyer, fence sign, open home posters and social media images. Buyers enquire directly with the owner. No agent, no commission, no platform branding on the property site.\n\nThis is the public, unauthenticated surface: a demo fence sign for any New Zealand street address, as a web page or a picture, plus an MCP server that returns the same. Nothing is created or stored against the address. Renders are rate limited per client (a few a minute); repeat requests for the same address are served from cache. Summary for assistants: https://homepage.org.nz/llms.txt",
    "contact": {
      "url": "https://homepage.org.nz/complaints"
    }
  },
  "servers": [
    {
      "url": "https://homepage.org.nz"
    }
  ],
  "paths": {
    "/sign": {
      "get": {
        "operationId": "signPage",
        "summary": "Demo fence sign for an address, as a web page",
        "description": "The picture, one paragraph on what it is, a preview of the whole marketing pack and a register-interest link. Has og:image, so the URL unfurls into the sign when pasted. The link to give a person.",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "Street address, for example \"12 Cottage Crescent\". Up to 60 characters.",
            "schema": {
              "type": "string",
              "maxLength": 60
            }
          },
          {
            "name": "suburb",
            "in": "query",
            "required": false,
            "description": "Suburb. Up to 40 characters.",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "description": "City or region. Up to 40 characters. Not printed on the sign; carried into the page title, the pack preview and the register link.",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          },
          {
            "name": "colour",
            "in": "query",
            "required": false,
            "description": "House colour as a six-digit hex value, for example #2d6a4f (URL-encode the # as %23). Homepage green by default.",
            "schema": {
              "type": "string",
              "pattern": "^#?[0-9a-fA-F]{6}$"
            }
          },
          {
            "name": "orientation",
            "in": "query",
            "required": false,
            "description": "Sheet orientation.",
            "schema": {
              "type": "string",
              "enum": [
                "landscape",
                "portrait"
              ],
              "default": "landscape"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML page",
            "content": {
              "text/html": {}
            }
          }
        }
      }
    },
    "/api/sign.png": {
      "get": {
        "operationId": "signImage",
        "summary": "Demo fence sign for an address, as a PNG",
        "description": "A \"This home is FOR SALE\" fence sign in Homepage's house style, marked \"Demo\", 1200 px on the long edge. Publicly cacheable for a day.",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "Street address, for example \"12 Cottage Crescent\". Up to 60 characters.",
            "schema": {
              "type": "string",
              "maxLength": 60
            }
          },
          {
            "name": "suburb",
            "in": "query",
            "required": false,
            "description": "Suburb. Up to 40 characters.",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "description": "City or region. Up to 40 characters. Not printed on the sign; carried into the page title, the pack preview and the register link.",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          },
          {
            "name": "colour",
            "in": "query",
            "required": false,
            "description": "House colour as a six-digit hex value, for example #2d6a4f (URL-encode the # as %23). Homepage green by default.",
            "schema": {
              "type": "string",
              "pattern": "^#?[0-9a-fA-F]{6}$"
            }
          },
          {
            "name": "orientation",
            "in": "query",
            "required": false,
            "description": "Sheet orientation.",
            "schema": {
              "type": "string",
              "enum": [
                "landscape",
                "portrait"
              ],
              "default": "landscape"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PNG image",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameter; the body says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "429": {
            "description": "Too many fresh renders from this client. Retry after the Retry-After seconds."
          },
          "503": {
            "description": "The renderer is not available on this server."
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "MCP server (Streamable HTTP, stateless, no auth)",
        "description": "JSON-RPC 2.0 over POST: initialize, ping, tools/list, tools/call. One tool, render_sign, taking the same parameters as /api/sign.png and returning the picture as an image content block plus pageUrl, imageUrl, previewUrl and registerUrl. GET answers 405; there is no server-to-client stream.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "A JSON-RPC 2.0 request or a batch of up to 8."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {}
            }
          },
          "202": {
            "description": "Notification accepted, nothing to return."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Usage": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "usage": {
            "type": "string"
          },
          "example": {
            "type": "string",
            "format": "uri"
          },
          "page": {
            "type": "string",
            "format": "uri"
          },
          "openapi": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    }
  }
}