{
  "openapi": "3.1.0",
  "info": {
    "title": "SolarX Philippines Public API",
    "version": "1.0.0",
    "description": "Public quote and discovery API for SolarX Philippines — solar installation leads for the Philippine market.",
    "contact": {
      "name": "SolarX Philippines",
      "url": "https://solarxphilippines.com/contact",
      "email": "hello@solarxphilippines.com"
    },
    "x-cli": {
      "package": "@solarxphilippines/cli",
      "documentation": "https://solarxphilippines.com/cli.md",
      "install": "npm install -g github:seankrux/solarxphilippines.com"
    }
  },
  "servers": [
    {
      "url": "https://solarxphilippines.com",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "quotes", "description": "Solar quote requests (WhatsApp handoff)" },
    { "name": "discovery", "description": "Agent and developer discovery" }
  ],
  "paths": {
    "/api": {
      "get": {
        "operationId": "getApiRoot",
        "tags": ["discovery"],
        "summary": "API root discovery",
        "description": "Entry point for agents: links to v1 discovery, OpenAPI, and the developer hub.",
        "responses": {
          "200": {
            "description": "API metadata and v1 discovery link",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiRoot" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      },
      "post": {
        "operationId": "apiRootMethodNotAllowed",
        "tags": ["discovery"],
        "summary": "Method not allowed on API root",
        "responses": {
          "405": {
            "description": "Use GET for discovery or POST /api/v1/quote for quotes",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/v1": {
      "get": {
        "operationId": "getApiV1Index",
        "tags": ["discovery"],
        "summary": "API v1 endpoint index",
        "description": "Lists versioned endpoints and documentation URLs.",
        "responses": {
          "200": {
            "description": "Versioned endpoint list",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiV1Index" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/v1/quote": {
      "post": {
        "operationId": "createQuoteRequest",
        "tags": ["quotes"],
        "summary": "Submit a solar quote request",
        "description": "Validates Philippine mobile numbers and returns a pre-filled WhatsApp deep link. Does not store leads server-side; requires end-user confirmation before opening WhatsApp.",
        "x-openai-isConsequential": false,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/QuoteRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote handoff created",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/QuoteSuccess" }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "headers": {
              "RateLimit-Limit": { "schema": { "type": "integer" } },
              "RateLimit-Remaining": { "schema": { "type": "integer" } },
              "RateLimit-Policy": { "schema": { "type": "string" } },
              "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds until the window resets" }
            },
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      },
      "get": {
        "operationId": "quoteV1MethodNotAllowed",
        "tags": ["quotes"],
        "summary": "Method not allowed",
        "description": "Quote submission requires POST with a JSON body.",
        "responses": {
          "405": {
            "description": "Use POST",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/quote": {
      "post": {
        "operationId": "createQuoteRequestLegacy",
        "tags": ["quotes"],
        "summary": "Submit a quote (legacy path)",
        "description": "Alias of POST /api/v1/quote for the website quote form. Prefer /api/v1/quote for new integrations.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/QuoteRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote handoff created",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/QuoteSuccess" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      },
      "get": {
        "operationId": "quoteLegacyMethodNotAllowed",
        "tags": ["quotes"],
        "summary": "Method not allowed (legacy path)",
        "responses": {
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/mcp": {
      "get": {
        "operationId": "getMcpDiscovery",
        "tags": ["discovery"],
        "summary": "MCP server discovery",
        "description": "Read-only MCP transport metadata and tool list for SolarX site agents.",
        "responses": {
          "200": {
            "description": "MCP discovery document",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/McpDiscovery" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      },
      "post": {
        "operationId": "mcpToolExecutionNotImplemented",
        "tags": ["discovery"],
        "summary": "Tool execution not available on HTTP",
        "responses": {
          "501": {
            "description": "Use browser WebMCP or read-only resources",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/problem+json": {
                "schema": { "$ref": "#/components/schemas/ProblemDetails" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpec",
        "tags": ["discovery"],
        "summary": "OpenAPI specification",
        "description": "Machine-readable API contract (this document).",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 document",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OpenApiDocument" }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimitLimit": {
        "schema": { "type": "integer", "example": 60 },
        "description": "Maximum requests allowed in the current window"
      },
      "RateLimitRemaining": {
        "schema": { "type": "integer", "example": 59 },
        "description": "Requests remaining in the current window"
      },
      "RateLimitPolicy": {
        "schema": { "type": "string", "example": "60;w=60" },
        "description": "Rate limit policy (limit;w=window seconds)"
      }
    },
    "responses": {
      "ValidationError": {
        "description": "Validation error",
        "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "HTTP method not allowed",
        "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limited",
        "headers": {
          "RateLimit-Limit": { "schema": { "type": "integer" } },
          "RateLimit-Remaining": { "schema": { "type": "integer" } },
          "RateLimit-Policy": { "schema": { "type": "string" } },
          "Retry-After": { "schema": { "type": "integer" } }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error",
        "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      }
    },
    "schemas": {
      "ApiRoot": {
        "type": "object",
        "required": ["name", "currentVersion", "discovery", "openapi", "developers"],
        "properties": {
          "name": { "type": "string" },
          "currentVersion": { "type": "string", "example": "v1" },
          "discovery": { "type": "string", "format": "uri" },
          "openapi": { "type": "string", "format": "uri" },
          "developers": { "type": "string", "format": "uri" }
        }
      },
      "ApiV1Index": {
        "type": "object",
        "required": ["version", "documentation", "openapi", "endpoints"],
        "properties": {
          "version": { "type": "string" },
          "documentation": { "type": "string", "format": "uri" },
          "openapi": { "type": "string", "format": "uri" },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["path", "methods", "description"],
              "properties": {
                "path": { "type": "string" },
                "methods": { "type": "array", "items": { "type": "string" } },
                "description": { "type": "string" }
              }
            }
          }
        }
      },
      "OpenApiDocument": {
        "type": "object",
        "description": "OpenAPI 3.1 specification object"
      },
      "QuoteRequest": {
        "type": "object",
        "required": ["name", "phone", "location", "monthlyBill"],
        "properties": {
          "name": { "type": "string", "minLength": 1 },
          "phone": { "type": "string", "description": "PH mobile: 09XX, +63 9XX, or 639XX" },
          "location": { "type": "string", "description": "City or service area" },
          "cityName": { "type": "string", "description": "Alias for location" },
          "monthlyBill": { "type": "string", "description": "Monthly electricity bill in PHP" },
          "roofType": { "type": "string" },
          "source": { "type": "string" },
          "message": { "type": "string" }
        }
      },
      "QuoteSuccess": {
        "type": "object",
        "required": ["ok", "whatsapp", "notifyPhone"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "whatsapp": { "type": "string", "format": "uri", "description": "WhatsApp deep link with encoded lead message" },
          "notifyPhone": { "type": "string" }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "required": ["type", "title", "status", "detail", "code"],
        "properties": {
          "type": { "type": "string", "format": "uri" },
          "title": { "type": "string" },
          "status": { "type": "integer" },
          "detail": { "type": "string" },
          "code": { "type": "string" },
          "instance": { "type": "string" }
        }
      },
      "McpDiscovery": {
        "type": "object",
        "required": ["protocol", "transport", "serverInfo", "tools"],
        "properties": {
          "protocol": { "type": "string", "example": "mcp" },
          "transport": { "type": "string", "example": "streamable-http" },
          "serverInfo": {
            "type": "object",
            "required": ["name", "version"],
            "properties": {
              "name": { "type": "string" },
              "version": { "type": "string" }
            }
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["name", "description", "inputSchema"],
              "properties": {
                "name": { "type": "string" },
                "description": { "type": "string" },
                "inputSchema": { "type": "object" }
              }
            }
          },
          "documentation": { "type": "string", "format": "uri" },
          "serverCard": { "type": "string", "format": "uri" }
        }
      }
    }
  },
  "x-api-versioning": {
    "current": "v1",
    "policy": "URL path versioning under /api/v1/. Breaking changes require a new major path (/api/v2/).",
    "deprecation": "Deprecated endpoints will return Deprecation and Sunset headers at least 90 days before removal.",
    "sunsetHeader": "Sunset",
    "deprecationHeader": "Deprecation"
  },
  "x-function-calling": {
    "notes": "Each operationId maps to a single HTTP method and path for LLM tool use.",
    "preferredQuoteOperation": "createQuoteRequest"
  }
}
