{
  "openapi": "3.1.0",
  "info": {
    "title": "Palm Beach Hot Tub Repair — public site API",
    "version": "1.0.0",
    "description": "Public endpoints behind palmbeachhottub.com. The only write endpoint (POST /api/lead) is Turnstile-protected and meant for the on-site callback form with a real user present; agents helping a user book a repair should open https://palmbeachhottub.com/contact/ or have the user call (561) 794-1557. Read-only data (pricing, service area, contact, symptom triage) is available without auth via the MCP endpoint at https://palmbeachhottub.com/mcp and as markdown from any page URL (Accept: text/markdown).",
    "contact": {
      "email": "service@palmbeachhottub.com",
      "url": "https://palmbeachhottub.com/contact/"
    }
  },
  "servers": [
    {
      "url": "https://palmbeachhottub.com"
    }
  ],
  "paths": {
    "/api/lead": {
      "post": {
        "operationId": "submitLead",
        "summary": "Submit a repair callback request (the site lead form)",
        "description": "Validates a Cloudflare Turnstile token, then emails the lead to our service inbox. Honeypot field `company` must be empty. Per-IP rate limited.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Customer name"
                  },
                  "phone": {
                    "type": "string",
                    "description": "Callback phone number (required, min 7 digits)"
                  },
                  "symptom": {
                    "type": "string",
                    "enum": [
                      "Won't heat",
                      "Not getting hot enough",
                      "FLO error",
                      "HL / low-flow error",
                      "Overheating (OH)",
                      "Sensor error (Sn)",
                      "Dry error (dr)",
                      "Tripping breaker",
                      "Heater element replacement",
                      "No jets",
                      "Pump won't run",
                      "Pump humming, won't spin",
                      "Pump making noise",
                      "Pump leaking",
                      "Low flow / weak jets",
                      "Air lock after refill",
                      "Circulation pump replacement",
                      "Control panel / topside dead",
                      "No power to the spa",
                      "Something else / not sure"
                    ],
                    "description": "What's wrong with the hot tub"
                  },
                  "city": {
                    "type": "string",
                    "enum": [
                      "West Palm Beach",
                      "Boca Raton",
                      "Boynton Beach",
                      "Delray Beach",
                      "Jupiter",
                      "Palm Beach Gardens",
                      "Wellington",
                      "Royal Palm Beach",
                      "Lake Worth Beach",
                      "Other PBC city"
                    ],
                    "description": "City in Palm Beach County"
                  },
                  "message": {
                    "type": "string",
                    "description": "Optional detail — brand, error code, what was already tried"
                  },
                  "page": {
                    "type": "string",
                    "description": "Page the request came from (defaults to the Referer)"
                  },
                  "cf-turnstile-response": {
                    "type": "string",
                    "description": "Cloudflare Turnstile token from the on-page widget (required — makes this endpoint effectively browser-only)"
                  },
                  "company": {
                    "type": "string",
                    "description": "Honeypot — must be left empty"
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "phone"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Customer name"
                  },
                  "phone": {
                    "type": "string",
                    "description": "Callback phone number (required, min 7 digits)"
                  },
                  "symptom": {
                    "type": "string",
                    "enum": [
                      "Won't heat",
                      "Not getting hot enough",
                      "FLO error",
                      "HL / low-flow error",
                      "Overheating (OH)",
                      "Sensor error (Sn)",
                      "Dry error (dr)",
                      "Tripping breaker",
                      "Heater element replacement",
                      "No jets",
                      "Pump won't run",
                      "Pump humming, won't spin",
                      "Pump making noise",
                      "Pump leaking",
                      "Low flow / weak jets",
                      "Air lock after refill",
                      "Circulation pump replacement",
                      "Control panel / topside dead",
                      "No power to the spa",
                      "Something else / not sure"
                    ],
                    "description": "What's wrong with the hot tub"
                  },
                  "city": {
                    "type": "string",
                    "enum": [
                      "West Palm Beach",
                      "Boca Raton",
                      "Boynton Beach",
                      "Delray Beach",
                      "Jupiter",
                      "Palm Beach Gardens",
                      "Wellington",
                      "Royal Palm Beach",
                      "Lake Worth Beach",
                      "Other PBC city"
                    ],
                    "description": "City in Palm Beach County"
                  },
                  "message": {
                    "type": "string",
                    "description": "Optional detail — brand, error code, what was already tried"
                  },
                  "page": {
                    "type": "string",
                    "description": "Page the request came from (defaults to the Referer)"
                  },
                  "cf-turnstile-response": {
                    "type": "string",
                    "description": "Cloudflare Turnstile token from the on-page widget (required — makes this endpoint effectively browser-only)"
                  },
                  "company": {
                    "type": "string",
                    "description": "Honeypot — must be left empty"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted — we call the customer back",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "403": {
            "description": "Turnstile verification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (POST only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "422": {
            "description": "Invalid phone number",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "502": {
            "description": "Lead delivery failed — call (561) 794-1557 instead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "health",
        "summary": "Liveness check",
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "service": {
                      "type": "string"
                    },
                    "at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Result": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}