{
  "openapi": "3.1.0",
  "info": {
    "title": "Cleveland Real Estate Group Lead API",
    "version": "1.0.0",
    "summary": "Send a cash-offer request, a contact message, or a buyers-list signup to Cleveland Real Estate Group.",
    "description": "Cleveland Real Estate Group buys houses in and around Cleveland, Ohio for cash. This API accepts the same submissions as the forms on clevelandrealestategroup.com and delivers them to the team by email.\n\nEvery submission must carry a Cloudflare Turnstile token (`cf-turnstile-response`). The token is issued by the Turnstile widget when it runs in a real browser with the public site key shown in the documentation, and it is verified server-side. Requests without a valid token are rejected with HTTP 400. Fully headless clients cannot obtain a token; agents acting for a person should drive a real browser session, or hand off to the web form or the phone number instead.\n\nSubmissions are rate limited per client IP. When the limit is hit the API answers HTTP 429 with a `Retry-After` header.",
    "termsOfService": "https://clevelandrealestategroup.com/terms-conditions/",
    "contact": {
      "name": "Cleveland Real Estate Group",
      "url": "https://clevelandrealestategroup.com/contact-us/"
    }
  },
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://clevelandrealestategroup.com/api/"
  },
  "servers": [
    { "url": "https://clevelandrealestategroup.com" }
  ],
  "tags": [
    { "name": "Leads", "description": "Submissions that reach the Cleveland Real Estate Group team." },
    { "name": "Status", "description": "Service health." }
  ],
  "paths": {
    "/api/submit": {
      "post": {
        "tags": ["Leads"],
        "operationId": "submitLead",
        "summary": "Submit a cash-offer request, contact message, or buyers-list signup",
        "description": "The `form-type` field selects which kind of submission is being sent and which other fields apply. The body is sent as form data, exactly as the site's own forms send it. A successful call emails the submission to the team and returns `{ \"success\": true }`.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": { "$ref": "#/components/schemas/Submission" }
            },
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/Submission" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submission accepted and emailed to the team.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SuccessResponse" },
                "example": { "success": true }
              }
            }
          },
          "400": {
            "description": "The Turnstile token was missing or invalid, or `form-type` was not one of the supported values.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "examples": {
                  "turnstile": { "value": { "error": "Turnstile verification failed" } },
                  "formType": { "value": { "error": "Unknown form type" } }
                }
              }
            }
          },
          "429": {
            "description": "Too many submissions from this client IP. Wait for the number of seconds given in `Retry-After` before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "example": 60 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": { "error": "Too many requests. Please try again later." }
              }
            }
          },
          "500": {
            "description": "The submission could not be delivered. Retry later or call the office.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": { "error": "Failed to send email" }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": ["Status"],
        "operationId": "getHealth",
        "summary": "Service health check",
        "description": "Returns `{ \"status\": \"ok\" }` when the API is up. Referenced by the `status` link in the RFC 9727 API catalog at `/.well-known/api-catalog`.",
        "responses": {
          "200": {
            "description": "The API is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["status"],
                  "properties": {
                    "status": { "type": "string", "const": "ok" }
                  }
                },
                "example": { "status": "ok" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Submission": {
        "description": "One of the three supported submission types, selected by `form-type`.",
        "oneOf": [
          { "$ref": "#/components/schemas/CashOfferRequest" },
          { "$ref": "#/components/schemas/ContactRequest" },
          { "$ref": "#/components/schemas/BuyersListRequest" }
        ],
        "discriminator": {
          "propertyName": "form-type",
          "mapping": {
            "cash-offer": "#/components/schemas/CashOfferRequest",
            "contact": "#/components/schemas/ContactRequest",
            "buyers-list": "#/components/schemas/BuyersListRequest"
          }
        }
      },
      "TurnstileToken": {
        "type": "string",
        "description": "Cloudflare Turnstile response token issued by the widget in the submitting browser. Verified server-side; single use."
      },
      "CashOfferRequest": {
        "type": "object",
        "description": "A homeowner asking for a no-obligation cash offer on a property in the Cleveland, Ohio area.",
        "required": ["form-type", "property-address", "phone-number", "email", "cf-turnstile-response"],
        "properties": {
          "form-type": { "type": "string", "const": "cash-offer" },
          "property-address": {
            "type": "string",
            "description": "Street address of the property to sell, including city and ZIP code.",
            "example": "1234 Detroit Ave, Lakewood, OH 44107"
          },
          "phone-number": {
            "type": "string",
            "description": "Phone number where the team can reach the seller.",
            "example": "216-555-0100"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Seller's email address."
          },
          "cf-turnstile-response": { "$ref": "#/components/schemas/TurnstileToken" }
        }
      },
      "ContactRequest": {
        "type": "object",
        "description": "A general message to the team.",
        "required": ["form-type", "first-name", "last-name", "email", "message", "cf-turnstile-response"],
        "properties": {
          "form-type": { "type": "string", "const": "contact" },
          "first-name": { "type": "string" },
          "last-name": { "type": "string" },
          "phone-number": { "type": "string", "description": "Optional callback number." },
          "email": { "type": "string", "format": "email" },
          "message": { "type": "string", "description": "The message body." },
          "cf-turnstile-response": { "$ref": "#/components/schemas/TurnstileToken" }
        }
      },
      "BuyersListRequest": {
        "type": "object",
        "description": "An investor or buyer asking to be notified about off-market properties that match their criteria.",
        "required": ["form-type", "name", "email", "phone", "zip-codes", "cf-turnstile-response"],
        "properties": {
          "form-type": { "type": "string", "const": "buyers-list" },
          "name": { "type": "string", "description": "Buyer's full name." },
          "email": { "type": "string", "format": "email" },
          "phone": { "type": "string" },
          "zip-codes": {
            "type": "string",
            "description": "Preferred ZIP codes or cities, free text.",
            "example": "44107, 44102, Parma"
          },
          "bedrooms": { "type": "string", "description": "Preferred number of bedrooms, free text." },
          "price-range": { "type": "string", "description": "Target purchase price range, free text.", "example": "$60k-$120k" },
          "close-timeline": { "type": "string", "description": "How quickly the buyer can close, free text.", "example": "14 days, cash" },
          "message": { "type": "string", "description": "Anything else the team should know." },
          "cf-turnstile-response": { "$ref": "#/components/schemas/TurnstileToken" }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "required": ["success"],
        "properties": {
          "success": { "type": "boolean", "const": true }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string" },
          "detail": { "type": "string", "description": "Present on some 500 responses with the upstream error text." }
        }
      }
    }
  }
}
