{
  "openapi": "3.0.3",
  "info": {
    "title": "Homesage.ai API",
    "version": "1.0.0",
    "description": "Property data, valuation, AI-powered analysis, skip tracing, and market intelligence — exposed as REST operations grouped into seven categories. See docs at https://homesage.ai/docs. **Address lookups & 404s are actionable:** endpoints that take a `property_address` resolve it to a single property; when it cannot be confidently matched they return HTTP 404 at 0 credits with a `did_you_mean` array of `{address, mpr_id}` suggestions — show these to the user and retry with a corrected full address (an empty array means no close match; see the `AddressLookupError` schema). This is why partial input like `4411` is rejected instead of being silently charged for the wrong property."
  },
  "paths": {
    "/api/area/autocomplete/": {
      "get": {
        "operationId": "area_autocomplete",
        "description": "\n## What it returns\n\nUp to 5 **area suggestions** (city, county, or ZIP) matching a partial place name — each a structured object you pass straight into the `location` filter of `preview_property_search` / `run_property_search`. This is how you turn \"Austin\" or \"Travis County\" into the exact object the search needs.\n\nDistinct from `auto_complete_address`: that resolves a single street address (for the single-property analysis tools); this resolves a search **area** (a whole city / county / ZIP) for database search.\n\n## When to use it\n\n- ALWAYS before a property search, to build the `location` filter. Don't hand-craft area objects — resolve them here so the city name, `state_code`, and county name match the database.\n- Pick the suggestion whose `type` (`city` / `county` / `postal_code`) matches what the user meant, then JSON-encode it as a one-element array for `location` — e.g. `location=[{the chosen suggestion}]`.\n\n## Pricing\n\n**Free — 0 credits.**\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | `input` missing. |\n| 404 | No areas matched the input. |\n",
        "summary": "Resolve a city / county / ZIP name into a search-area object (free)",
        "parameters": [
          {
            "in": "query",
            "name": "input",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Partial area name to resolve — a city, county, or ZIP (e.g. \"Austin\", \"Travis County\", \"78704\"). Street addresses are not returned (use `auto_complete_address` for those).",
            "example": "Austin"
          }
        ],
        "tags": ["Property Search"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "City + county suggestions",
                    "value": {
                      "outcome": "success",
                      "data": [
                        {
                          "text": "Austin, TX, USA",
                          "type": "city",
                          "state": "Texas",
                          "state_code": "TX",
                          "county": "Travis",
                          "city": "Austin",
                          "areas": [],
                          "zip_code": ""
                        },
                        {
                          "text": "Travis County, TX, USA",
                          "type": "county",
                          "state": "Texas",
                          "state_code": "TX",
                          "county": "Travis",
                          "city": "",
                          "areas": ["Travis"],
                          "zip_code": ""
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": "Up to 5 area suggestions. Each row drops straight into the search `location` filter."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "`input` query parameter missing. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "No areas matched the input. Costs 0 credits."
          }
        },
        "x-slug": "area-autocomplete",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/area/autocomplete/?input=Austin' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/area/autocomplete/', params={'input': 'Austin'}, headers={'Authorization': 'Token YOUR_API_KEY'})\nprint(r.json())"
          }
        ],
        "x-playground": "enabled",
        "x-credits": 0
      }
    },
    "/api/workspace/search/count/": {
      "get": {
        "operationId": "preview_property_search",
        "description": "\n## What it returns\n\nA **free preview** of a property-database search: `count` (how many properties match the filters) and `cost` (the credits the full search would charge). **This call never charges credits.**\n\nThis is the mandatory safety step before `run_property_search`. The charged search costs **1 credit per matching property**, so a broad filter set can cost thousands of credits. Always preview here, tell the user the count and cost, and get an explicit yes before running the paid search.\n\n## When to use it\n\n- ALWAYS before `run_property_search`, to size and price the result set.\n- To tighten filters (narrow the location, add a price band / condition / ROI floor) until the count and cost fit the user's budget.\n- To confirm a search returns anything before spending.\n\n## Required filters\n\nEvery search needs a `location` (a city, county, or ZIP — not a whole state), a `property_status`, AND at least one investment filter (price range, property type, condition, investment-potential grade, ROI range, …). The investment-filter rule keeps results pertinent and cost-effective. It can be waived with `allow_location_only=true`, but a location-only search in a dense metro can match thousands of properties — check the cost first.\n\n## Pricing\n\n**Free — 0 credits.** Only `run_property_search` charges.\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | Required filters missing — the `missing` array names them (`location`, `property_status`, and/or `investment_lens`). |\n| 401 | Authentication failed. |\n| 402 | No active subscription. |\n",
        "summary": "Preview a property-database search — free match count + credit cost",
        "parameters": [
          {
            "in": "query",
            "name": "location",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A JSON-encoded array of one or more area objects. City: `{\"type\":\"city\",\"city\":\"Austin\",\"state_code\":\"TX\"}`; county: `{\"type\":\"county\",\"county\":\"Travis County\",\"state_code\":\"TX\"}`; ZIP: `{\"type\":\"postal_code\",\"zip_code\":\"78704\",\"state_code\":\"TX\"}`. State-wide scope is not supported.",
            "example": "[{\"type\":\"city\",\"city\":\"Austin\",\"state_code\":\"TX\"}]"
          },
          {
            "in": "query",
            "name": "property_status",
            "required": true,
            "schema": {
              "type": "string",
              "enum": ["active", "pending", "sold", "any"]
            },
            "description": "Listing status to search. `active`/`pending` search live for-sale listings; `sold` searches historical sales (enables the `from`/`to` date range); `any` = active + pending.",
            "example": "active"
          },
          {
            "in": "query",
            "name": "price_min",
            "schema": {
              "type": "integer"
            },
            "description": "Minimum price in USD (list price for for-sale, sold price for sold).",
            "example": 100000
          },
          {
            "in": "query",
            "name": "price_max",
            "schema": {
              "type": "integer"
            },
            "description": "Maximum price in USD.",
            "example": 500000
          },
          {
            "in": "query",
            "name": "property_type",
            "schema": {
              "type": "string"
            },
            "description": "Pipe-delimited property types. One or more of: `detached|townhouse|apartment|multi family|other`.",
            "example": "detached|townhouse"
          },
          {
            "in": "query",
            "name": "property_condition",
            "schema": {
              "type": "string"
            },
            "description": "Pipe-delimited condition grades (Homesage.ai ML-derived). One or more of: `excellent|good|outdated|very poor|poor|unlivable`.",
            "example": "outdated|poor"
          },
          {
            "in": "query",
            "name": "investment_potential_grades",
            "schema": {
              "type": "string"
            },
            "description": "Pipe-delimited investment-potential grades (for-sale only). Codes: `excel` (ROI ≥ 35%), `high` (25–35%), `med` (15–25%), `low` (5–15%), `noPot` (< 5%).",
            "example": "excel|high"
          },
          {
            "in": "query",
            "name": "roi_min",
            "schema": {
              "type": "number"
            },
            "description": "Minimum projected ROI, as a percentage (e.g. `15` = 15%).",
            "example": 15
          },
          {
            "in": "query",
            "name": "roi_max",
            "schema": {
              "type": "number"
            },
            "description": "Maximum projected ROI percentage.",
            "example": 50
          },
          {
            "in": "query",
            "name": "dom",
            "schema": {
              "type": "integer"
            },
            "description": "Days-on-market ceiling (for-sale only): only listings listed within the last N days.",
            "example": 30
          },
          {
            "in": "query",
            "name": "from",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Sold-search only: earliest sold date (ISO-8601, `YYYY-MM-DD`).",
            "example": "2024-01-01"
          },
          {
            "in": "query",
            "name": "to",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Sold-search only: latest sold date (ISO-8601, `YYYY-MM-DD`).",
            "example": "2024-12-31"
          },
          {
            "in": "query",
            "name": "allow_location_only",
            "schema": {
              "type": "string",
              "enum": ["true", "false"]
            },
            "description": "Set `true` to waive the investment-filter requirement and search by location + status alone. Use with care — location-only searches can match thousands of properties. Location and status remain required.",
            "example": "false"
          }
        ],
        "tags": ["Property Search"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Free count + cost",
                    "value": {
                      "count": 1240,
                      "cost": 1240
                    }
                  }
                }
              }
            },
            "description": "Match count and the credit cost of running the full search. No charge."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Required filters missing. The `missing` array lists the unmet obligations. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid credential. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "No active subscription. Costs 0 credits."
          }
        },
        "x-slug": "preview-property-search",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/workspace/search/count/?location=%5B%7B%22type%22%3A%22city%22%2C%22city%22%3A%22Austin%22%2C%22state_code%22%3A%22TX%22%7D%5D&property_status=active&price_min=100000&price_max=500000&property_condition=outdated%7Cpoor' -H 'Authorization: Token YOUR_API_KEY'"
          }
        ],
        "x-playground": "enabled",
        "x-credits": 0
      }
    },
    "/api/workspace/search/": {
      "post": {
        "operationId": "run_property_search",
        "description": "\n## What it returns\n\nThe full set of properties matching your investment filters — each with valuation, investment metrics, condition, and location detail. This is the **charged** database search.\n\n## ⚠️ Cost — read before calling\n\n**1 credit per property returned.** A search that matches 1,200 properties costs **1,200 credits**. Charging is all-or-nothing: if the balance can't cover the whole set, nothing is charged and the call returns `402`.\n\n**Always call `preview_property_search` first**, show the user the count and cost, and get an explicit yes before calling this. Never run a broad or location-only search without confirming the cost.\n\n## When to use it\n\n- After `preview_property_search` and explicit user confirmation of the credit cost.\n- To pull a curated, filtered list of investment properties for an area.\n\n## Required filters\n\nSame as `preview_property_search`: a `location` (city/county/ZIP), a `property_status`, and at least one investment filter (or `allow_location_only=true` to waive only the investment filter). Send the SAME filters you previewed so the cost matches.\n\n## Pricing\n\n**1 credit per matching property**, charged all-or-nothing on success. `400`/`401`/`402` cost 0 credits.\n",
        "summary": "Search the property database by investment criteria (1 credit per result)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["location", "property_status"],
                "properties": {
                  "location": {
                    "type": "string",
                    "description": "A JSON-encoded array of one or more area objects. City: `{\"type\":\"city\",\"city\":\"Austin\",\"state_code\":\"TX\"}`; county: `{\"type\":\"county\",\"county\":\"Travis County\",\"state_code\":\"TX\"}`; ZIP: `{\"type\":\"postal_code\",\"zip_code\":\"78704\",\"state_code\":\"TX\"}`. State-wide scope is not supported."
                  },
                  "property_status": {
                    "type": "string",
                    "enum": ["active", "pending", "sold", "any"],
                    "description": "Listing status to search. `active`/`pending` search live for-sale listings; `sold` searches historical sales (enables the `from`/`to` date range); `any` = active + pending."
                  },
                  "price_min": {
                    "type": "integer",
                    "description": "Minimum price in USD."
                  },
                  "price_max": {
                    "type": "integer",
                    "description": "Maximum price in USD."
                  },
                  "property_type": {
                    "type": "string",
                    "description": "Pipe-delimited: `detached|townhouse|apartment|multi family|other`."
                  },
                  "property_condition": {
                    "type": "string",
                    "description": "Pipe-delimited: `excellent|good|outdated|very poor|poor|unlivable`."
                  },
                  "investment_potential_grades": {
                    "type": "string",
                    "description": "Pipe-delimited (for-sale only): `excel|high|med|low|noPot`."
                  },
                  "roi_min": {
                    "type": "number",
                    "description": "Minimum projected ROI percentage."
                  },
                  "roi_max": {
                    "type": "number",
                    "description": "Maximum projected ROI percentage."
                  },
                  "dom": {
                    "type": "integer",
                    "description": "Days-on-market ceiling (for-sale only)."
                  },
                  "from": {
                    "type": "string",
                    "format": "date",
                    "description": "Sold-search only: earliest sold date (YYYY-MM-DD)."
                  },
                  "to": {
                    "type": "string",
                    "format": "date",
                    "description": "Sold-search only: latest sold date (YYYY-MM-DD)."
                  },
                  "allow_location_only": {
                    "type": "boolean",
                    "description": "Waive ONLY the investment-filter requirement (location + status still required). Use with care — can match thousands of properties."
                  }
                }
              },
              "examples": {
                "SearchByFilters": {
                  "summary": "Distressed homes in Austin under $500k",
                  "value": {
                    "location": "[{\"type\":\"city\",\"city\":\"Austin\",\"state_code\":\"TX\"}]",
                    "property_status": "active",
                    "price_max": 500000,
                    "property_condition": "outdated|poor|very poor"
                  }
                }
              }
            }
          }
        },
        "tags": ["Property Search"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Charged search result",
                    "value": {
                      "count": 1240,
                      "charged": 1240,
                      "credits_left": 8760,
                      "search_id": "0c7c…",
                      "data": [
                        {
                          "property_id": "…",
                          "address": "1203 W 9th St, Austin, TX 78703",
                          "list_price": 480000,
                          "roi": 0.21,
                          "property_condition": "outdated"
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": "The full matching result set. `charged` credits (= `count`) were deducted; `credits_left` is the new balance."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Required filters missing. The `missing` array lists the unmet obligations. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "No active subscription, OR insufficient credits for the whole set (nothing was charged — the body carries `credits_left` and `required`)."
          }
        },
        "x-slug": "run-property-search",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://developers.homesage.ai/api/workspace/search/' \\\n  -H 'Authorization: Token YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"location\": \"[{\\\"type\\\":\\\"city\\\",\\\"city\\\":\\\"Austin\\\",\\\"state_code\\\":\\\"TX\\\"}]\", \"property_status\": \"active\", \"price_max\": 500000, \"property_condition\": \"outdated|poor\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests, json\nr = requests.post(\n    'https://developers.homesage.ai/api/workspace/search/',\n    json={\n        'location': json.dumps([{'type': 'city', 'city': 'Austin', 'state_code': 'TX'}]),\n        'property_status': 'active',\n        'price_max': 500000,\n        'property_condition': 'outdated|poor',\n    },\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nprint(r.json())"
          }
        ],
        "x-playground": "confirm",
        "x-credits": 1,
        "x-credits-unit": "property"
      }
    },
    "/api/properties/auto-complete/": {
      "get": {
        "operationId": "auto_complete_address",
        "description": "\n## What it returns\n\nUp to 5 address suggestions matching a partial address string. Powered by a national address graph and curated to US street-level results only — city names, state codes, and ZIP codes alone return no matches.\n\n## When to use it\n\n- Power a typeahead input on a \"lookup property\" form.\n- Resolve user-typed input to a canonical address string before calling `info` / `current-estimate`.\n- Disambiguate between similar-named streets in the same city.\n\n## Pricing\n\n**Free — 0 credits.** Safe to fire on every keystroke (debounce in the client recommended for cost-of-network, not credits).\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | `input` parameter missing or shorter than 2 characters. |\n| 401 | Authentication failed. |\n| 503 | Upstream address service unavailable. Retry with backoff. |\n\n## FAQ\n\n### Does this work for commercial addresses?\nNo. Only US residential street addresses are returned. The endpoint upstream filters to `area_type == \"address\"` records only.\n\n### Can I autocomplete by ZIP code?\nNo — ZIP-only input returns an empty `data` array. Provide a street fragment with at least one number or street word.\n",
        "summary": "Suggest US property addresses from a partial string",
        "parameters": [
          {
            "in": "query",
            "name": "input",
            "schema": {
              "type": "string"
            },
            "description": "Partial address. Minimum 2 characters. Example: `4411 E Hidden`.",
            "required": true,
            "example": "4411 E Hidden"
          }
        ],
        "tags": ["Property Lookup"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AutoCompleteResponse"
                },
                "examples": {
                  "SingleMatch": {
                    "value": {
                      "outcome": "success",
                      "data": [
                        {
                          "text": "4411 E Hidden Oak St, Springfield, MO, 65802, USA",
                          "address": "4411 E Hidden Oak St, Springfield, MO, 65802, USA",
                          "city": "Springfield",
                          "postal_code": "65802",
                          "state_code": "MO"
                        }
                      ],
                      "search_input": "4411 E Hidden",
                      "results_count": 1
                    },
                    "summary": "Single match"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "`input` is missing or shorter than 2 characters."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream address service is unavailable. Retry with backoff."
          }
        },
        "x-slug": "auto-complete",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/auto-complete/?input=4411%20E%20Hidden' \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nr = requests.get(\n    'https://developers.homesage.ai/api/properties/auto-complete/',\n    params={'input': '4411 E Hidden'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nfor s in r.json()['data']:\n    print(s['address'])"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL('https://developers.homesage.ai/api/properties/auto-complete/');\nurl.searchParams.set('input', '4411 E Hidden');\nconst r = await fetch(url, { headers: { Authorization: 'Token YOUR_API_KEY' } });"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 0
      }
    },
    "/api/properties/pfs/": {
      "get": {
        "operationId": "get_price_flexibility_score",
        "description": "## What it returns\n\nA **Price Flexibility Score (PFS)** for an active or recently-sold property — an estimate of how much price-negotiation room a listing has, derived from days-on-market, price-change history, comparable activity, and seasonal demand. Higher score = more flexible (buyer can negotiate down more).\n\n## When to use it\n\n- Suggest a target offer percentage to a buyer.\n- Sort lead lists by negotiation opportunity.\n- Trigger an alert when a watched property's PFS climbs.\n\n## Pricing\n\n2 credits.\n\n## FAQ\n\n### Does PFS work on sold properties?\nYes — historical PFS at sale time, useful for model backtesting.\n\n### Is PFS the same as AVM?\nNo. AVM estimates *what the property is worth*. PFS estimates *how movable the asking price is* — orthogonal questions.",
        "summary": "Price Flexibility Score — how much room a listing has to negotiate",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "pfs": 1.43
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "price-flexibility-score",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/pfs/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/pfs/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 2
      }
    },
    "/api/properties/investment_potential/": {
      "get": {
        "operationId": "get_investment_potential",
        "description": "## What it returns\n\nAn **Investment Potential** score plus the component sub-scores it's built from (price relative to comps, cash-flow potential, appreciation trajectory, neighborhood risk). Designed as a first-pass filter for investor screening.\n\n## When to use it\n\n- Rank a watchlist of properties by overall investment quality.\n- Power a 'top opportunities in your market' feed.\n\n## Pricing\n\n3 credits.\n\n## FAQ\n\n### Is the score a percentage?\nA 0–100 composite. Higher = better. Sub-scores are individually weighted; see the response's `breakdown` block.\n\n### Does it account for my financing assumptions?\nNo — it's a property-level score, not deal-specific. For deal-level returns, use `flip-return` or `rental-long-term`.",
        "summary": "Composite investor-grade investment-potential score",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "investment_potential": 0
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "investment-potential",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/investment_potential/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/investment_potential/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 3
      }
    },
    "/api/properties/info/": {
      "get": {
        "operationId": "get_property_info",
        "description": "\n## What it returns\n\nFull property record for a single US residential property — address, coordinates, listing status and price, AVM-estimated value, size, days on market, building/lot/parking/interior breakdown, listing-office details, recent property history, and nearby school ratings. Sourced from a national listing graph + Homesage.ai's AVM, hydrated on the first call per property and cached.\n\n## When to use it\n\n- Render a property-detail page in your UI.\n- Enrich a CRM lead record with the latest listing status and AVM.\n- Cross-check a third-party AVM against Homesage.ai's.\n- Look up listing-office contact info from a property address.\n\n## Pricing\n\n**2 credits per successful call.** `null` returns from missing source data still cost 2 credits because the upstream call still ran. `404`/`401`/`402` cost 0 credits.\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | Neither `property_address` nor `property_id` provided, or `property_id` is not valid base64. |\n| 401 | Authentication failed. |\n| 402 | No subscription, or out of credits. |\n| 404 | The autocomplete suggestion didn't match a real listing. Response includes `did_you_mean` suggestions. |\n\n## FAQ\n\n### What's the difference between `info` and `updated-info`?\n`info` is the fast lookup and may serve recently stored data. `updated-info` always returns the freshest available record (slower). Use `updated-info` when stale data matters — pricing decisions, just-listed alerts, post-sale follow-ups.\n\n### Why is `listing_price` `null`?\nThe property is not currently listed for sale. `estimated_value` (AVM) is still populated when available.\n\n### Can I look up by `property_id` instead of address?\nYes — pass `property_id` as a base64-encoded string. Use the `id` field returned by `auto-complete`.\n\n### How fresh are school ratings?\nRefreshed annually from national school-ratings data.\n",
        "summary": "Full property record for a US residential property",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "description": "Full US property address to look up.",
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Lookup"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PropertyInfoResponse"
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                      "coordinates": {
                        "latitude": 37.227381,
                        "longitude": -93.201372
                      },
                      "list_date": "2026-06-02T17:11:07Z",
                      "status": "Pending/Under Contract",
                      "listing_price": 575000,
                      "estimated_value": 576722.09,
                      "sf": 2351,
                      "psf": 244.58,
                      "dom": 6,
                      "property_features": {
                        "beds": 3,
                        "full_baths": 2,
                        "half_baths": 1,
                        "stories": 1,
                        "basement": false,
                        "style": "",
                        "new_construction": false,
                        "year_built": 2024,
                        "cooling": "Central Air, Ceiling Fan(s)",
                        "garage": 3
                      },
                      "location_community": {
                        "property_type": "Single Family",
                        "ownership": "Other",
                        "hoa": true,
                        "hoa_fee": 65,
                        "county": "Greene",
                        "neighborhood": "The Lakes Wild Horse",
                        "subdivision": "The Lakes Wild Horse",
                        "school_district": "",
                        "structure": "",
                        "waterfront": ""
                      },
                      "building_info": {
                        "above_grade_size": 2351,
                        "below_grade_size": 0,
                        "total_size": 2351,
                        "elevator": "",
                        "foundation_details": "Poured Concrete, Vapor Barrier",
                        "construction_materials": "Hardboard Siding, Brick Full",
                        "building_exterior_type": "Hardboard Siding, Brick Full",
                        "roof": "Composition",
                        "flooring": "Carpet, Engineered Hardwood, Tile",
                        "parking": "Garage Faces Front, Paved"
                      },
                      "lot": {
                        "lot_acres": 0.26,
                        "lot_sqft": 11326,
                        "fencing": "Wood",
                        "lot_features": "Rain Gutters, Fencing: Wood, Patio And Porch Features: Patio, Covered, Deck, Road Frontage Type: City Street, Road Surface Type: Asphalt, Concrete, Patio: Yes, Deck: Yes"
                      },
                      "parking": {
                        "total_parking_spaces": "3",
                        "features": ""
                      },
                      "interior_features": ["Internet - Fiber Optic", "Quartz Counters"],
                      "home_value": [
                        {
                          "month": "05",
                          "year": "2026",
                          "estimate": 575607.88
                        },
                        {
                          "month": "04",
                          "year": "2026",
                          "estimate": 591801.1
                        }
                      ],
                      "utilities": ["Sewer: Public Sewer", "Water Source: City"],
                      "listing_office": {
                        "agent_name": "Graddy Real Estate",
                        "agent_2_name": "",
                        "agent_email": "info@adamgraddy.com",
                        "agent_phone_mobile": "(417) 501 5091",
                        "agent_phone_office": "(417) 883 4900",
                        "responsible_broker": "Keller Williams Realty - Greater Springfield",
                        "office_address": "1619 East Independence Street, SPRINGFIELD, MO 65804",
                        "office_name": "Keller Williams Realty Local",
                        "office_phone": null,
                        "office_email": "jbolin@kw.com",
                        "office_website": "http://springfieldkw.yourkwoffice.com/",
                        "office_slogan": "#1 Training Organization in the World",
                        "mls_set": "O-SPMO-512000534"
                      },
                      "listing_details": {
                        "type_of_sale": "Standard",
                        "zoning": "",
                        "listing_date": "2026-06-02T17:11:07Z",
                        "mls_name": "SOMO",
                        "mls_id": "60325257",
                        "tax_amt": 3841
                      },
                      "property_history": [
                        {
                          "event_name": "Listed",
                          "date": "2026-06-02",
                          "price": 575000,
                          "price_per_sqft": 244.57677584006805,
                          "source_listing_id": "60325257",
                          "source_name": "SOMO"
                        },
                        {
                          "event_name": "Listing removed",
                          "date": "2026-06-01",
                          "price": 0,
                          "price_per_sqft": null,
                          "source_listing_id": "60318192",
                          "source_name": "SOMO"
                        }
                      ],
                      "school_ratings": [
                        {
                          "name": "Hickory Hills Middle School",
                          "rating": 9,
                          "parent_rating": 3,
                          "distance_in_miles": 0.5,
                          "grades": ["6", "7"],
                          "student_count": 414,
                          "funding_type": "public",
                          "education_levels": ["middle"]
                        },
                        {
                          "name": "Hickory Hills Elementary School",
                          "rating": 8,
                          "parent_rating": 3,
                          "distance_in_miles": 0.5,
                          "grades": ["K", "1"],
                          "student_count": 353,
                          "funding_type": "public",
                          "education_levels": ["elementary"]
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "`property_address` is missing or could not be resolved to a property."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "info",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/info/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nr = requests.get(\n    'https://developers.homesage.ai/api/properties/info/',\n    params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nprint(r.json()['estimated_value'])"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL('https://developers.homesage.ai/api/properties/info/');\nurl.searchParams.set('property_address', '4411 E Hidden Oak St Springfield MO 65802');\nconst r = await fetch(url, { headers: { Authorization: 'Token YOUR_API_KEY' } });"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 2
      }
    },
    "/api/properties/updated-info/": {
      "get": {
        "operationId": "get_updated_property_info",
        "description": "Identical response shape to `info` — see that endpoint's docs for fields and FAQ. The difference: `info` is the fast lookup and may serve recently stored data; `updated-info` always returns the freshest available record. Use this when freshness matters more than the ~2-second latency cost — pricing decisions, just-listed alerts, post-sale confirmation. **Costs 1 credit per call** (cheaper than `info` because the cache hit-rate doesn't apply).",
        "summary": "Same as `info` but always force-fetches fresh data from the source",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "description": "Full US property address to re-fetch fresh from the source.",
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Lookup"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PropertyInfoResponse"
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                      "coordinates": {
                        "latitude": 37.227381,
                        "longitude": -93.201372
                      },
                      "list_date": "2026-06-02T17:11:07Z",
                      "status": "Pending/Under Contract",
                      "listing_price": 575000,
                      "estimated_value": 576722.09,
                      "sf": 2351,
                      "psf": 244.58,
                      "dom": 6,
                      "property_features": {
                        "beds": 3,
                        "full_baths": 2,
                        "half_baths": 1,
                        "stories": 1,
                        "basement": false,
                        "style": "",
                        "new_construction": false,
                        "year_built": 2024,
                        "cooling": "Central Air, Ceiling Fan(s)",
                        "garage": 3
                      },
                      "location_community": {
                        "property_type": "Single Family",
                        "ownership": "Other",
                        "hoa": true,
                        "hoa_fee": 65,
                        "county": "Greene",
                        "neighborhood": "The Lakes Wild Horse",
                        "subdivision": "The Lakes Wild Horse",
                        "school_district": "",
                        "structure": "",
                        "waterfront": ""
                      },
                      "building_info": {
                        "above_grade_size": 2351,
                        "below_grade_size": 0,
                        "total_size": 2351,
                        "elevator": "",
                        "foundation_details": "Poured Concrete, Vapor Barrier",
                        "construction_materials": "Hardboard Siding, Brick Full",
                        "building_exterior_type": "Hardboard Siding, Brick Full",
                        "roof": "Composition",
                        "flooring": "Carpet, Engineered Hardwood, Tile",
                        "parking": "Garage Faces Front, Paved"
                      },
                      "lot": {
                        "lot_acres": 0.26,
                        "lot_sqft": 11326,
                        "fencing": "Wood",
                        "lot_features": "Rain Gutters, Fencing: Wood, Patio And Porch Features: Patio, Covered, Deck, Road Frontage Type: City Street, Road Surface Type: Asphalt, Concrete, Patio: Yes, Deck: Yes"
                      },
                      "parking": {
                        "total_parking_spaces": "3",
                        "features": ""
                      },
                      "interior_features": ["Internet - Fiber Optic", "Quartz Counters"],
                      "home_value": [
                        {
                          "month": "05",
                          "year": "2026",
                          "estimate": 589043.84
                        },
                        {
                          "month": "04",
                          "year": "2026",
                          "estimate": 585807.65
                        }
                      ],
                      "utilities": ["Sewer: Public Sewer", "Water Source: City"],
                      "listing_office": {
                        "agent_name": "Graddy Real Estate",
                        "agent_2_name": "",
                        "agent_email": "info@adamgraddy.com",
                        "agent_phone_mobile": "(417) 501 5091",
                        "agent_phone_office": "(417) 883 4900",
                        "responsible_broker": "Keller Williams Realty - Greater Springfield",
                        "office_address": "1619 East Independence Street, SPRINGFIELD, MO 65804",
                        "office_name": "Keller Williams Realty Local",
                        "office_phone": null,
                        "office_email": "jbolin@kw.com",
                        "office_website": "http://springfieldkw.yourkwoffice.com/",
                        "office_slogan": "#1 Training Organization in the World",
                        "mls_set": "O-SPMO-512000534"
                      },
                      "listing_details": {
                        "type_of_sale": "Standard",
                        "zoning": "",
                        "listing_date": "2026-06-02T17:11:07Z",
                        "mls_name": "SOMO",
                        "mls_id": "60325257",
                        "tax_amt": 3841
                      },
                      "property_history": [
                        {
                          "event_name": "Listed",
                          "date": "2026-06-02",
                          "price": 575000,
                          "price_per_sqft": 244.57677584006805,
                          "source_listing_id": "60325257",
                          "source_name": "SOMO"
                        },
                        {
                          "event_name": "Listing removed",
                          "date": "2026-06-01",
                          "price": 0,
                          "price_per_sqft": null,
                          "source_listing_id": "60318192",
                          "source_name": "SOMO"
                        }
                      ],
                      "school_ratings": [
                        {
                          "name": "Hickory Hills Middle School",
                          "rating": 9,
                          "parent_rating": 3,
                          "distance_in_miles": 0.5,
                          "grades": ["6", "7"],
                          "student_count": 414,
                          "funding_type": "public",
                          "education_levels": ["middle"]
                        },
                        {
                          "name": "Hickory Hills Elementary School",
                          "rating": 8,
                          "parent_rating": 3,
                          "distance_in_miles": 0.5,
                          "grades": ["K", "1"],
                          "student_count": 353,
                          "funding_type": "public",
                          "education_levels": ["elementary"]
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "`property_address` is missing or could not be resolved to a property."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "updated-info",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/updated-info/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nr = requests.get(\n    'https://developers.homesage.ai/api/properties/updated-info/',\n    params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL('https://developers.homesage.ai/api/properties/updated-info/');\nurl.searchParams.set('property_address', '4411 E Hidden Oak St Springfield MO 65802');\nconst r = await fetch(url, { headers: { Authorization: 'Token YOUR_API_KEY' } });"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/renovation_return/": {
      "get": {
        "operationId": "get_renovation_return",
        "description": "## What it returns\n\nProjected return analysis assuming a standard renovation is performed: pre-renovation AVM, projected post-renovation ARV (After Repair Value), renovation cost estimate (see `renovation-cost` for a breakdown), and net return + ROI percent.\n\n## When to use it\n\n- Evaluate buy-and-fix-up opportunities.\n- Compare renovation vs. cosmetic-only strategies on a single property.\n\n## Pricing\n\n3 credits.\n\n## FAQ\n\n### What renovation scope is assumed?\nA mid-grade full-interior refresh. For a custom scope, use `renovation-cost` with explicit room-level inputs.\n\n### How is ARV calculated?\nFrom renovated comps in the same micro-market, adjusted for size and condition delta. See `comps` for the underlying comparable set.",
        "summary": "Projected return after renovating a property",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "pre_renovation_avm": 250000,
                      "post_renovation_arv": 340000,
                      "renovation_cost": 40000,
                      "value_increase": 90000,
                      "net_return": 50000,
                      "roi_percent": 125.0,
                      "max_recommended_renovation_budget": 66200
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "renovation-return",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/renovation_return/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/renovation_return/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 3
      }
    },
    "/api/properties/flip_return/": {
      "get": {
        "operationId": "get_flip_return",
        "description": "## What it returns\n\nA fix-and-flip return summary for the property — four numbers:\n\n- `total_project_cost` — all-in cost: acquisition + renovation + holding + financing.\n- `profit` — projected profit at resale, net of selling costs.\n- `resale_roi` — return on investment, as a percent of total project cost (can be negative).\n- `max_recommended_renovation_budget` — the renovation-spend ceiling that keeps the deal profitable.\n\nDiffers from `renovation-return` by folding holding and financing costs into the project total.\n\n## When to use it\n\n- Underwrite flip candidates with a standard model.\n- Sort lead lists by projected flip ROI.\n\n## Pricing\n\n3 credits.\n\n## FAQ\n\n### What financing terms are assumed?\nHard-money standard — 70% LTC, 12% interest, 2 points, 6-month hold. Override is on the roadmap.\n\n### Does it deduct agent commissions?\nYes — 6% commission + 1.5% closing assumed on the sale side.",
        "summary": "End-to-end fix-and-flip return projection",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "total_project_cost": 721724.15,
                      "profit": -3775.36,
                      "resale_roi": -0.52,
                      "max_recommended_renovation_budget": 94819.37
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "flip-return",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/flip_return/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/flip_return/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 3
      }
    },
    "/api/properties/home_value_graph/": {
      "get": {
        "operationId": "get_home_value_history",
        "description": "## What it returns\n\nA time-series of monthly AVM estimates for a property over the last 5 years. Designed to plot value-over-time charts and detect inflection points (renovation, neighborhood revaluation, market cycle).\n\n## When to use it\n\n- Render a value-history chart on a property detail page.\n- Detect properties whose value diverged from their neighborhood trend.\n\n## Pricing\n\n1 credit.\n\n## FAQ\n\n### How far back does the history go?\nUp to 60 months. New construction has shorter history. Pre-MLS-era properties may have gaps.",
        "summary": "Historical AVM trajectory for a property",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "home_value_graph": [
                        {
                          "date": "2026-06",
                          "value": 567840.56
                        },
                        {
                          "date": "2026-05",
                          "value": 579097.16
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "home-value-history",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/home_value_graph/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/home_value_graph/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/tlc/": {
      "get": {
        "operationId": "check_needs_tlc",
        "description": "## What it returns\n\nA boolean / confidence-scored flag indicating whether the property is likely a **fixer-upper** — i.e. needs material renovation to reach market potential. Built from the AI property-condition signal, photo-based wear indicators, listing-language NLP (detects 'cash offers only', 'as-is', 'investor special'), and pricing relative to comps.\n\n## When to use it\n\n- Filter MLS results to fixer-upper candidates for flip investors.\n- Pre-flag listings for wholesale outreach.\n\n## Pricing\n\n1 credit.\n\n## FAQ\n\n### What does TLC stand for?\n'Tender Loving Care' — real estate slang for a property needing meaningful work. Same as fixer-upper.\n\n### Why might a clearly-rough property return `false`?\nWhen the listing is priced at market rate (suggesting the seller is asking move-in-ready prices), the signal is weak even if condition is poor.",
        "summary": "Does this property need TLC (fixer-upper indicator)?",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "is_tlc": true
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "needs-tlc-check",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/tlc/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/tlc/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/rental/long_term/": {
      "get": {
        "operationId": "get_long_term_rental",
        "description": "## What it returns\n\nProjected long-term rental income — monthly rent band, vacancy assumption, gross operating income, net operating income after standard expense ratios, and capitalization rate vs. the AVM. Built from MLS-comparable rentals in the same micro-market.\n\n## When to use it\n\n- Underwrite buy-and-hold rental candidates.\n- Compute cap rates across a watchlist.\n\n## Pricing\n\n5 credits.\n\n## FAQ\n\n### What's included in the expense assumption?\nProperty management (8%), maintenance (5%), vacancy (5%), insurance, property tax. Mortgage cost is NOT included — these are pre-debt-service numbers (NOI).",
        "summary": "Long-term (12-month-lease) rental projection",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "Daily Gross": 73.77,
                      "Daily Net": 6.8,
                      "Monthly Gross": 2212.99,
                      "Monthly Net": 203.97,
                      "Annual Gross": 26555.88,
                      "Annual Net": 2447.64,
                      "Rental IRR": -10.75,
                      "Long-Term Cash Flow": 2235,
                      "Long-Term Cap Rate": 0.39,
                      "Net Operating Income (NOI)": 2235.23,
                      "Cash-on-Cash": 0.34
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "rental-long-term",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/rental/long_term/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/rental/long_term/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 5
      }
    },
    "/api/properties/rental/short_term/": {
      "get": {
        "operationId": "get_short_term_rental",
        "description": "## What it returns\n\nProjected short-term rental performance — nightly rate band, expected occupancy, monthly gross income, net of typical expense ratios. Built from STR comparables in the same micro-market.\n\n## When to use it\n\n- Evaluate STR opportunities for buy-and-host investors.\n- Compare LTR vs. STR income on the same property.\n\n## Pricing\n\n5 credits.\n\n## FAQ\n\n### Does it account for local STR regulations?\nNo — markets with STR bans/caps may produce projections that aren't operationally achievable. Verify local rules before underwriting.",
        "summary": "Short-term (Airbnb-style) rental projection",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "irr_percentage": 0.005688686236027252,
                      "cash_flow_monthly": 1522,
                      "cash_flow_annually": 18264,
                      "cap_rate": 3.188268470759285,
                      "short_term_monthly_gross": 3697.21,
                      "short_term_annual_gross": 44366.49,
                      "short_term_noi_monthly": 1522.06,
                      "short_term_noi_annual": 18264.75,
                      "short_term_daily_gross": 123.24,
                      "short_term_monthly_net": 1522.07,
                      "short_term_daily_net": 50.74,
                      "short_term_annual_net": 18264.84,
                      "short_term_cash_on_cash": 2.81
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "rental-short-term",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/rental/short_term/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/rental/short_term/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 5
      }
    },
    "/api/properties/renovation/cost/": {
      "get": {
        "operationId": "get_renovation_cost",
        "description": "## What it returns\n\nAn aggregate estimated renovation cost for a property, plus the sqft basis and the per-sqft cost-of-construction model used. For a room-by-room breakdown with material/labor split, use `renovation-cost-breakdown` instead.\n\n## When to use it\n\n- Quick screening of fix-and-flip cost before detailed underwriting.\n- Feed into `flip-return` for an end-to-end deal-level projection.\n\n## Pricing\n\n5 credits.\n\n## FAQ\n\n### What renovation scope is assumed?\nA standard mid-grade refresh. Use `renovation-cost-breakdown` for explicit room/scope control.",
        "summary": "Total renovation cost estimate (top-level)",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "renovation_cost": 58775,
                      "full_potential": 717948.79,
                      "spread": 142948.79,
                      "value_gap": 24.86,
                      "estimated_value_increase": 145075.79
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "renovation-cost",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/renovation/cost/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/renovation/cost/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 5
      }
    },
    "/api/properties/full-report/": {
      "get": {
        "operationId": "get_full_report",
        "description": "## What it returns\n\nThe most comprehensive property analysis endpoint — aggregates **11 internal sources** into a single response with **292 data fields**. One call instead of orchestrating a dozen individual endpoints.\n\n**Includes:**\n\n- Property photos (exclusive to this endpoint)\n- Property info, valuation, condition\n- Investment potential, flip / resale analysis\n- Rental projections, renovation cost\n- Home value history, school ratings, local data\n- Comparable properties\n\n**Does NOT include:**\n\n- Solar analysis — call `/solar/analysis/` separately (4 credits)\n- Mortgage / lien data\n- Skip tracing / owner information\n\n## When to use it\n\n- Render a deep property-analysis dashboard page.\n- One-shot underwriting export for an investor.\n- Train ML models on multi-signal property snapshots.\n\n## Performance\n\n**This is the slowest, most expensive endpoint — it runs the full AI pipeline and comp search end-to-end. Use a 120-second client timeout and cache responses.**\n\n## Pricing\n\n**15 credits per request** — about **25% cheaper** than calling the individual endpoints separately (~20 credits).\n\n## Data availability\n\nBecause this aggregates many internal sources, sub-fields may be `null`, `0`, or empty arrays when the underlying data is unavailable for a property — e.g. `comps` may be empty in rural areas, `last_sold_price` is `0` in non-disclosure states, and `photos` can be empty for unlisted properties.\n\n## FAQ\n\n### Why is this so much more than the individual endpoints?\nIt runs the AI condition pipeline and comp search end-to-end. The value vs. calling endpoints individually is one round-trip and guaranteed shape consistency.\n\n### Can I disable sub-sections to save credits?\nNot currently — the report is all-or-nothing. Call the individual endpoints if you only need specific signals.",
        "summary": "Composite full property report — everything aggregated",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["AI-Powered Analysis"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "photos": [
                        {
                          "href": "https://developers.scaladom.com/api/properties/image/aHR0cDovL2FwLnJkY3BpeC5jb20vMGZlNmRmNWMwZjMxYWQ0MTZlMTY1YjIwMmI2MTU4ZTdsLW0zNzMyOTMzNDUwcy13MTAyNF9oNzY4X3gyLmpwZw==/"
                        },
                        {
                          "href": "https://developers.scaladom.com/api/properties/image/aHR0cDovL2FwLnJkY3BpeC5jb20vMGZlNmRmNWMwZjMxYWQ0MTZlMTY1YjIwMmI2MTU4ZTdsLW00MjkwMTI0NjE2cy13MTAyNF9oNzY4X3gyLmpwZw==/"
                        }
                      ],
                      "investment_potential": 0,
                      "property_value": {
                        "investment_potential": 0,
                        "listing_price": 575000,
                        "price_per_sf": 244.58,
                        "avm": 583410.33,
                        "full_potential": 697833.73,
                        "spread": 122833.72999999998,
                        "value_gap": 21,
                        "estimated_value_increase": 124960.73,
                        "Estimated_Property_Value": 572873,
                        "LP/FP": 82,
                        "LP/ARV": 0.824,
                        "last_sold_price": 0,
                        "last_sold_date": "2025-02-10",
                        "avm_confidence": "insufficient",
                        "avm_low": null,
                        "avm_high": null,
                        "avm_computed_at": "2026-06-08T21:13:13.916857+00:00",
                        "avm_comps_count": 0
                      },
                      "avm_comps": [],
                      "purchased_held": {
                        "roi": 112.61,
                        "new_equity": 66185.73,
                        "total_project_cost": 664288.25,
                        "cash_needed_at_purchase": 592250,
                        "closing_cost_at_purchase": 17250
                      },
                      "resale_potential": {
                        "total_project_cost": 720114.95,
                        "profit": -22281.22,
                        "roi": -3.1,
                        "new_equity": 66185.73,
                        "cash_from_sale": 642007.03,
                        "cash_needed_for_purchase": 592250,
                        "closing_cost_at_purchase": 17250,
                        "closing_cost_at_sale": 55826.7
                      },
                      "rental_potential": {
                        "long_term": {
                          "monthly_revenue": 2212.99,
                          "monthly_cash_flow": 186.25,
                          "annual_revenue": 26555.88,
                          "annual_cash_flow": 2235,
                          "irr": -10.75,
                          "cap_rate": 0.39,
                          "cash_on_cash": 0.34,
                          "expense_breakdown": {
                            "property_tax_monthly": 320,
                            "insurance_monthly": 239,
                            "hoa_monthly": 5,
                            "maintenance_monthly": 716,
                            "vacancy_monthly": 192,
                            "management_monthly": 221,
                            "miscellaneous_monthly": 477
                          }
                        },
                        "short_term": {
                          "monthly_revenue": 3214.96,
                          "monthly_cash_flow": 191.83,
                          "annual_revenue": 38579.55,
                          "annual_cash_flow": 2302,
                          "irr": -8.87,
                          "cap_rate": 0.4,
                          "cash_on_cash": 0.35,
                          "expense_breakdown": {
                            "property_tax_monthly": 320,
                            "insurance_monthly": 153,
                            "hoa_monthly": 5,
                            "cleaning_monthly": 306,
                            "utilities_monthly": 19,
                            "platform_fees_monthly": 230,
                            "maintenance_monthly": 716,
                            "supplies_monthly": 115,
                            "management_monthly": 643
                          }
                        }
                      },
                      "pfs": {
                        "pfs": 2.86
                      },
                      "tlc": {
                        "tlc": true,
                        "tlc_level": null
                      },
                      "renovation_cost": {
                        "estimated_renovation_cost": 58775,
                        "maximum_recommended_renovation_budget": 76112.3689
                      },
                      "property_info": {
                        "address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                        "longitude": -93.201372,
                        "latitude": 37.227381,
                        "state_code": "MO",
                        "status": "Pending/Under Contract",
                        "property_condition": "Good",
                        "sf": 2351,
                        "dom": 6,
                        "property_features": {
                          "beds": 3,
                          "full_baths": 2,
                          "half_baths": 1,
                          "stories": 1,
                          "basement": false,
                          "style": "",
                          "new_construction": false,
                          "year_built": 2024,
                          "cooling": "Central Air, Ceiling Fan(s)",
                          "garage": 3
                        },
                        "location_community": {
                          "property_type": "Single Family",
                          "ownership": "Other",
                          "hoa": true,
                          "hoa_fee": 65,
                          "county": "Greene",
                          "neighborhood": "The Lakes Wild Horse",
                          "subdivision": "The Lakes Wild Horse",
                          "school_district": "",
                          "structure": "",
                          "waterfront": ""
                        },
                        "building_info": {
                          "above_grade_size": 2351,
                          "below_grade_size": 0,
                          "total_size": 2351,
                          "elevator": "",
                          "foundation_details": "Poured Concrete, Vapor Barrier",
                          "construction_materials": "Hardboard Siding, Brick Full",
                          "building_exterior_type": "Hardboard Siding, Brick Full",
                          "roof": "Composition",
                          "flooring": "Carpet, Engineered Hardwood, Tile",
                          "parking": "Garage Faces Front, Paved"
                        },
                        "lot": {
                          "lot_acres": "0.2600",
                          "lot_sqft": 11326,
                          "fencing": "Wood",
                          "lot_features": "Rain Gutters, Fencing: Wood, Patio And Porch Features: Patio, Covered, Deck, Road Frontage Type: City Street, Road Surface Type: Asphalt, Concrete, Patio: Yes, Deck: Yes"
                        },
                        "parking": {
                          "total_parking_spaces": "3",
                          "features": ""
                        },
                        "interior_features": ["Internet - Fiber Optic", "Quartz Counters"],
                        "utilities": ["Sewer: Public Sewer", "Water Source: City"]
                      },
                      "home_value_graph": {
                        "home_value_graph": [
                          {
                            "month": "05",
                            "year": "2026",
                            "estimate": 581803.14
                          },
                          {
                            "month": "04",
                            "year": "2026",
                            "estimate": 594891.41
                          }
                        ]
                      },
                      "listing_details": {
                        "listing_office": {
                          "agent_name": "Graddy Real Estate",
                          "agent_2_name": "",
                          "agent_email": "info@adamgraddy.com",
                          "agent_phone_mobile": "(417) 501 5091",
                          "agent_phone_office": "(417) 883 4900",
                          "responsible_broker": "Keller Williams Realty - Greater Springfield",
                          "office_address": "1619 East Independence Street, SPRINGFIELD, MO 65804",
                          "office_name": "Keller Williams Realty Local",
                          "office_phone": null,
                          "office_email": "jbolin@kw.com",
                          "office_website": "http://springfieldkw.yourkwoffice.com/",
                          "office_slogan": "#1 Training Organization in the World",
                          "mls_set": "O-SPMO-512000534"
                        },
                        "listing_details": {
                          "type_of_sale": "Standard",
                          "zoning": "",
                          "listing_date": "2026-06-02T17:11:07Z",
                          "mls_name": "SOMO",
                          "mls_id": "60325257",
                          "tax_amt": 3841
                        },
                        "property_history": [
                          {
                            "event_name": "Listed",
                            "date": "2026-06-02",
                            "price": 575000,
                            "price_per_sqft": 244.57677584006805,
                            "source_listing_id": "60325257",
                            "source_name": "SOMO"
                          },
                          {
                            "event_name": "Listing removed",
                            "date": "2026-06-01",
                            "price": 0,
                            "price_per_sqft": null,
                            "source_listing_id": "60318192",
                            "source_name": "SOMO"
                          }
                        ]
                      },
                      "schools": {
                        "schools": [
                          {
                            "name": "Hickory Hills Middle School",
                            "rating": 9,
                            "parent_rating": 3,
                            "distance_in_miles": 0.5,
                            "grades": ["6", "7"],
                            "student_count": 414,
                            "funding_type": "public",
                            "education_levels": ["middle"]
                          },
                          {
                            "name": "Hickory Hills Elementary School",
                            "rating": 8,
                            "parent_rating": 3,
                            "distance_in_miles": 0.5,
                            "grades": ["K", "1"],
                            "student_count": 353,
                            "funding_type": "public",
                            "education_levels": ["elementary"]
                          }
                        ]
                      },
                      "local": {
                        "flood": {
                          "flood_factor_severity": "minimal",
                          "flood_trend": "This property’s flood risk is not changing.",
                          "fema_zone": ["X (unshaded)"]
                        },
                        "wildfire": {
                          "fire_factor_severity": "Minimal",
                          "fire_trend": "This property’s wildfire risk is not changing."
                        },
                        "noise": {
                          "score": null,
                          "noise_categories": [
                            {
                              "text": null,
                              "type": "airport"
                            },
                            {
                              "text": null,
                              "type": "traffic"
                            }
                          ]
                        }
                      },
                      "comps": [
                        {
                          "_id": "694735232198c7bc3f323909",
                          "address": "4436 E Kentbrook Drive, Springfield, MO 65802",
                          "location": {
                            "address": {
                              "line": "4436 E Kentbrook Drive",
                              "city": "Springfield",
                              "state_code": "MO",
                              "postal_code": "65802"
                            }
                          },
                          "total_size": 1974,
                          "beds": 4,
                          "baths": 2,
                          "baths_full": null,
                          "baths_half": null,
                          "description": {
                            "beds": 4,
                            "baths": 2,
                            "baths_full": null,
                            "baths_half": null,
                            "total_size": 1974,
                            "type": "SINGLE_FAMILY"
                          },
                          "original_last_sold_price": 0,
                          "adjusted_last_sold_price": 0,
                          "last_sold_price": 0,
                          "last_sold_date": "2025-12-18",
                          "distance": 102.39782839572364,
                          "coordinate": {
                            "type": "Point",
                            "coordinates": [-93.20184, 37.22654]
                          },
                          "latitude": 37.22654,
                          "longitude": -93.20184,
                          "property_type": "SINGLE_FAMILY",
                          "external_estimate": 407000,
                          "photos": [],
                          "final_property_condition": "Good",
                          "condition_source": "photo_analysis",
                          "_data_source": "listing_feed",
                          "reference_only": true,
                          "comp_confidence_score": 95.2,
                          "type_match": true,
                          "used_for_arv": false,
                          "neighborhood": "N/A",
                          "property_condition": "Good"
                        },
                        {
                          "_id": "694735232198c7bc3f323a99",
                          "address": "4427 E Kentbrook Drive, Springfield, MO 65802",
                          "location": {
                            "address": {
                              "line": "4427 E Kentbrook Drive",
                              "city": "Springfield",
                              "state_code": "MO",
                              "postal_code": "65802"
                            }
                          },
                          "total_size": 2227,
                          "beds": 4,
                          "baths": 2,
                          "baths_full": null,
                          "baths_half": null,
                          "description": {
                            "beds": 4,
                            "baths": 2,
                            "baths_full": null,
                            "baths_half": null,
                            "total_size": 2227,
                            "type": "SINGLE_FAMILY"
                          },
                          "original_last_sold_price": 0,
                          "adjusted_last_sold_price": 0,
                          "last_sold_price": 0,
                          "last_sold_date": "2025-11-21",
                          "distance": 149.11351072926874,
                          "coordinate": {
                            "type": "Point",
                            "coordinates": [-93.202415, 37.22633]
                          },
                          "latitude": 37.22633,
                          "longitude": -93.202415,
                          "property_type": "SINGLE_FAMILY",
                          "external_estimate": 430000,
                          "photos": [],
                          "final_property_condition": "Good",
                          "condition_source": "photo_analysis",
                          "_data_source": "listing_feed",
                          "reference_only": true,
                          "comp_confidence_score": 95.8,
                          "type_match": true,
                          "used_for_arv": false,
                          "neighborhood": "N/A",
                          "property_condition": "Good"
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "full-report",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/full-report/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/full-report/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 15
      }
    },
    "/api/properties/property-condition/": {
      "get": {
        "operationId": "get_property_condition",
        "description": "## What it returns\n\nAn **AI condition assessment** for a US residential property — overall condition category (Excellent/Good/Fair/Poor), confidence score, per-room breakdown when photos are available, and any flags (water damage, deferred maintenance signals). Built from a computer-vision pipeline on the listing's photo set.\n\n## When to use it\n\n- Filter MLS feeds to move-in-ready vs. fixer candidates.\n- Adjust AVM expectations based on actual condition.\n- Pre-screen photos to skip a manual review pass.\n\n## Pricing\n\n2 credits.\n\n## FAQ\n\n### What model is used?\nA multimodal AI vision pipeline; specific models aren't disclosed. Outputs are described in domain terms (`Excellent`, `Good`, …) so the contract is stable across model swaps.\n\n### Does it work on listings without photos?\nNo — returns `null` overall and a low confidence score. Use `property-condition-custom-photos` to upload your own (NB: that endpoint is currently broken; see [DEVELOPER_API_REPORT.md]).",
        "summary": "AI-derived property condition score from listing photos",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["AI-Powered Analysis"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "Property Condition": "Good"
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "property-condition",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/property-condition/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/property-condition/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 2
      }
    },
    "/api/properties/property-condition-custom-photos/": {
      "post": {
        "operationId": "property_condition_custom_photos",
        "description": "## What it returns\n\nAn overall property-condition rating and confidence score, combining a database lookup with AI vision analysis of property photos you supply. Providing images yields a more accurate assessment than the address-only `property-condition` endpoint.\n\n## Performance\n\n**Image analysis is slow — use a 60-second client timeout and cache responses.**\n\n## Input modes\n\n- **Address only** — database lookup (same as `property-condition`).\n- **Image URLs** — pass `image_urls`, comma-separated (up to 25).\n- **File upload** — `POST multipart/form-data` with an `images` field (up to 15 files).\n- **Combined** — address + images for the most accurate result.\n\n**Costs 3 credits per call.**",
        "summary": "Property condition analysis with your own photos",
        "tags": ["AI-Powered Analysis"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PropertyConditionCustomPhotosRequestRequest"
              },
              "examples": {
                "AddressOnly": {
                  "value": {
                    "address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                  },
                  "summary": "Address only"
                },
                "Address+ImageURLs": {
                  "value": {
                    "address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                    "image_urls": "https://example.com/photo1.jpg,https://example.com/photo2.jpg"
                  },
                  "summary": "Address + image URLs"
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PropertyConditionCustomPhotosRequestRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PropertyConditionCustomPhotosRequestRequest"
              }
            }
          }
        },
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "property_condition": "Good",
                      "confidence_score": 0.85,
                      "details": {},
                      "address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          }
        },
        "x-slug": "property-condition-custom-photos",
        "x-playground": "enabled",
        "x-credits": 3,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \"https://developers.homesage.ai/api/properties/property-condition-custom-photos/\" \\\n  -H \"Authorization: Bearer $HOMESAGE_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    \"https://developers.homesage.ai/api/properties/property-condition-custom-photos/\",\n    json={\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"},\n    headers={\"Authorization\": \"Bearer YOUR_API_KEY\"},\n)\nprint(resp.json())"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL(\"https://developers.homesage.ai/api/properties/property-condition-custom-photos/\");\nconst res = await fetch(url, {\n  method: \"POST\",\n  headers: { \"Authorization\": \"Bearer YOUR_API_KEY\", \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"}),\n});\nconst data = await res.json();"
          }
        ]
      }
    },
    "/api/properties/sqft-per-floor/": {
      "get": {
        "operationId": "get_sqft_per_floor",
        "description": "## What it returns\n\nPer-floor square-footage distribution for a US residential property, derived from a multi-stage AI analysis (photo/room detection, architectural-style inference, and multi-method validation). Returns the total square footage and a `square_feet_by_floor` map keyed by floor.\n\n## When to use it\n\n- Break out living area by floor for renovation, valuation, or listing copy.\n- Sanity-check a single total-sqft figure against a per-floor split.\n\n**Note:** this is a heavy AI workflow — use a **45-second client timeout**.\n\n**Costs 1 credit per call.**",
        "summary": "AI-powered square-footage breakdown by floor",
        "parameters": [
          {
            "in": "query",
            "name": "address",
            "schema": {
              "type": "string"
            },
            "description": "Full US property address. Example: `4411 E Hidden Oak St Springfield MO 65802`.",
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["AI-Powered Analysis"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "total_square_feet": 2351,
                      "square_feet_by_floor": {
                        "Floor_1": 2351
                      },
                      "address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "sqft-per-floor",
        "x-playground": "enabled",
        "x-credits": 1,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://developers.homesage.ai/api/properties/sqft-per-floor/?address=4411%20E%20Hidden%20Oak%20St%2C%20Springfield%2C%20MO%2C%2065802\" \\\n  -H \"Authorization: Bearer $HOMESAGE_API_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    \"https://developers.homesage.ai/api/properties/sqft-per-floor/\",\n    params={\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"},\n    headers={\"Authorization\": \"Bearer YOUR_API_KEY\"},\n)\nprint(resp.json())"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL(\"https://developers.homesage.ai/api/properties/sqft-per-floor/\");\nurl.searchParams.set(\"address\", \"4411 E Hidden Oak St, Springfield, MO, 65802\");\nconst res = await fetch(url, {\n  method: \"GET\",\n  headers: { \"Authorization\": \"Bearer YOUR_API_KEY\" },\n});\nconst data = await res.json();"
          }
        ]
      }
    },
    "/api/properties/comps/": {
      "get": {
        "operationId": "get_comps",
        "description": "## What it returns\n\nA ranked list of **comparable sold properties** within a search radius of the subject — each comp scored on similarity (size, beds/baths, year built, distance, condition delta) with the sale price and date. Powers AVM and ARV computations.\n\n## When to use it\n\n- Build a comps table on a property report page.\n- Validate AVM against the comparable set it's derived from.\n- Power custom value models with raw comp inputs.\n\n## Performance\n\n**This is a slow endpoint — use a 60-second client timeout and cache responses.**\n\n## Pricing\n\n5 credits.\n\n## FAQ\n\n### How are comps ranked?\nBy a weighted similarity score that favors smaller size/feature deltas and shorter geographic distance. Sold date recency is a strong negative weight on older sales.\n\n### Does it adjust for condition?\nYes — if both the subject and comp have AI-condition scores, prices are adjusted up/down for the condition delta.\n\n## Fallback parameters\n\nYou can pass user-supplied values for the attributes the comp model uses, as **fallbacks**: Homesage.ai data is always used when available; your value is used only when our record is missing that field — so verified data is never overridden. Supported fallbacks: `total_size`, `bedrooms`, `bathrooms`, `property_type`. Only `total_size` can unblock an otherwise-empty result; the others just refine comp matching. `year_built` is intentionally **not** a factor in the comp/ARV model.\n\nEvery response includes a `field_sources` object telling you where each value came from: `homesage` (our data), `user_provided` (your fallback), or `unavailable`.",
        "summary": "Comparable sold properties (comps) for a subject property",
        "parameters": [
          {
            "in": "query",
            "name": "bathrooms",
            "schema": {
              "type": "number"
            },
            "description": "Fallback bathroom count. Refines comp matching when Homesage.ai is missing it; used only as a fallback.",
            "example": 2
          },
          {
            "in": "query",
            "name": "bedrooms",
            "schema": {
              "type": "integer"
            },
            "description": "Fallback bedroom count. Refines comp matching when Homesage.ai is missing it; used only as a fallback.",
            "example": 4
          },
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          },
          {
            "in": "query",
            "name": "property_type",
            "schema": {
              "type": "string"
            },
            "description": "Fallback property type, e.g. `single_family`. Refines comp matching when Homesage.ai is missing it; used only as a fallback.",
            "example": "single_family"
          },
          {
            "in": "query",
            "name": "total_size",
            "schema": {
              "type": "integer"
            },
            "description": "Fallback square footage. Used only when Homesage.ai has no size on record — supplying it unblocks an otherwise-empty result. Verified Homesage.ai data is never overridden.",
            "example": 1500
          }
        ],
        "tags": ["AI-Powered Analysis"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "arv": null,
                      "arv_confidence": "insufficient",
                      "comps_found_total": 0,
                      "warning": "This property is in a non-disclosure state (MO). Sale prices are not publicly recorded, which limits available comp data. 5 comp(s) are shown as reference only (no disclosed sale price) and were not used in the ARV calculation. ARV could not be calculated due to insufficient price data.",
                      "comps": [
                        {
                          "address": "4427 E Kentbrook Drive, Springfield, MO 65802",
                          "distance": "0.09",
                          "size": 2227.0,
                          "beds": 4,
                          "baths": 2.0,
                          "baths_full": null,
                          "baths_half": null,
                          "sold_price": 0,
                          "adjusted_price": 0,
                          "sold_date": "2025-11-21",
                          "property_condition": "Good",
                          "confidence_score": 95.8,
                          "reference_only": true
                        },
                        {
                          "address": "4436 E Kentbrook Drive, Springfield, MO 65802",
                          "distance": "0.06",
                          "size": 1974.0,
                          "beds": 4,
                          "baths": 2.0,
                          "baths_full": null,
                          "baths_half": null,
                          "sold_price": 0,
                          "adjusted_price": 0,
                          "sold_date": "2025-12-18",
                          "property_condition": "Good",
                          "confidence_score": 95.2,
                          "reference_only": true
                        }
                      ],
                      "size_source": "homesage",
                      "field_sources": {
                        "total_size": "homesage",
                        "bedrooms": "homesage",
                        "bathrooms": "homesage",
                        "property_type": "homesage"
                      }
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          }
        },
        "x-slug": "comps",
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 5,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://developers.homesage.ai/api/properties/comps/?property_address=4411%20E%20Hidden%20Oak%20St%2C%20Springfield%2C%20MO%2C%2065802&total_size=1500&bedrooms=4&bathrooms=2&property_type=single_family\" \\\n  -H \"Authorization: Bearer $HOMESAGE_API_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    \"https://developers.homesage.ai/api/properties/comps/\",\n    params={\"property_address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\", \"total_size\": 1500, \"bedrooms\": 4, \"bathrooms\": 2, \"property_type\": \"single_family\"},\n    headers={\"Authorization\": \"Bearer YOUR_API_KEY\"},\n)\nprint(resp.json())"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL(\"https://developers.homesage.ai/api/properties/comps/\");\nurl.searchParams.set(\"property_address\", \"4411 E Hidden Oak St, Springfield, MO, 65802\");\nurl.searchParams.set(\"total_size\", \"1500\");\nurl.searchParams.set(\"bedrooms\", \"4\");\nurl.searchParams.set(\"bathrooms\", \"2\");\nurl.searchParams.set(\"property_type\", \"single_family\");\nconst res = await fetch(url, {\n  method: \"GET\",\n  headers: { \"Authorization\": \"Bearer YOUR_API_KEY\" },\n});\nconst data = await res.json();"
          }
        ]
      }
    },
    "/api/properties/bulk-info/": {
      "get": {
        "operationId": "bulk_property_info",
        "description": "\n## What it returns\n\nPaginated search across all US residential properties matching geo + price + bed/bath/sqft/year-built/DOM/lot filters. Each result row carries ROI-relevant fields (AVM bands, financing/holding/project-cost breakdowns, potential ROI) — designed to feed investor screening dashboards, not detail pages.\n\n## When to use it\n\n- Build investor screening with multi-criteria filters (e.g. \"active listings under $300k in zip 65802 with potential_roi > 0.15\").\n- Generate market reports: average AVM, average days on market, count of matches.\n- Seed a recommendation engine with filtered candidate pools.\n\n## Performance\n\n**This is a slow endpoint — use a 60-second client timeout and cache responses.**\n\n## Pricing\n\n**1 credit per property in the response.** A page with 50 properties costs 50 credits. Use `page_size` to cap cost — for screening UI, smaller pages with manual paginate-on-demand is the cost-effective pattern.\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | Invalid filter values (e.g. `min_price > max_price`, non-numeric `beds_max`). |\n| 401 | Authentication failed. |\n| 402 | No subscription or insufficient credits for the page size requested. |\n| 503 / 504 | Backend datastore unavailable or query timed out. |\n\n## FAQ\n\n### What's the difference between `property_status: \"Active\"` and `\"Sold\"`?\n`Active` queries `residential_for_sale`. `Sold` queries `residential_sold` (same backing as the dedicated `sold-by-zip` endpoint). Both share the same response shape.\n\n### Why is `dom` calculated rather than stored?\nThe MLS doesn't always carry days-on-market natively. When the field is absent, the endpoint computes it from `list_date` to `sold_date` (or to \"now\" for active listings).\n\n### Can I filter by neighborhood?\nNot directly. Filter by city + state + zip; the response includes a `neighborhood` field for client-side post-filtering.\n\n### Is `avm_confidence` a percentage?\nA `0.0`–`1.0` float. Higher = the AVM model is more confident in the band. Filter on `avm_confidence > 0.7` for high-quality estimates only.\n",
        "summary": "Paginated, filterable property search with ROI fields",
        "parameters": [
          {
            "in": "query",
            "name": "city",
            "schema": {
              "type": "string"
            },
            "description": "City name to search within.\n\n**At least one** of `zip`, `city`, or `state` is required."
          },
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer"
            },
            "description": "1-based page number. Defaults to 1.",
            "example": 1
          },
          {
            "in": "query",
            "name": "page_size",
            "schema": {
              "type": "integer"
            },
            "description": "Items per page. Defaults to 20. Caps your per-call credit cost.",
            "example": 5
          },
          {
            "in": "query",
            "name": "state",
            "schema": {
              "type": "string"
            },
            "description": "2-letter US state code.\n\n**At least one** of `zip`, `city`, or `state` is required."
          },
          {
            "in": "query",
            "name": "zip",
            "schema": {
              "type": "string"
            },
            "description": "5-digit US ZIP code to search within.\n\n**At least one** of `zip`, `city`, or `state` is required.",
            "example": "65802"
          }
        ],
        "tags": ["Property Lookup"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPropertyInfoResponse"
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "total_count": 208,
                      "page": 1,
                      "page_size": 5,
                      "total_pages": 42,
                      "properties": [
                        {
                          "address": {
                            "city": "Springfield",
                            "line": "2900 W Lombard St",
                            "postal_code": "65802",
                            "state": "Missouri",
                            "state_code": "MO",
                            "coordinate": {
                              "lat": 37.198301,
                              "lon": -93.335912
                            },
                            "street_direction": "W",
                            "street_name": "Lombard",
                            "street_number": "2900",
                            "street_post_direction": null,
                            "street_suffix": "St",
                            "unit": null,
                            "validation_code": "121"
                          },
                          "list_price": 189900,
                          "description": {
                            "baths": 2,
                            "baths_full": 2,
                            "baths_half": null,
                            "baths_consolidated": "2",
                            "beds": 2,
                            "garage": null,
                            "garage_type": null,
                            "lot_sqft": 18731,
                            "sqft": 896,
                            "stories": 1,
                            "type": "single_family",
                            "sub_type": null,
                            "year_built": 1907,
                            "name": null,
                            "construction": null,
                            "cooling": null,
                            "exterior": null,
                            "fireplace": null,
                            "heating": null,
                            "pool": null,
                            "roofing": null,
                            "rooms": null,
                            "styles": null,
                            "units": null,
                            "year_renovated": null,
                            "zoning": null
                          },
                          "status": "for_sale",
                          "last_update_date": "2026-06-08T17:23:32Z",
                          "neighborhood": null,
                          "final_property_condition": "Poor",
                          "photo_analysis": null,
                          "condition_source": "CV",
                          "post_renovation_value": 129054.98,
                          "potential": 0,
                          "roi": 84.69,
                          "profit": 59177.04,
                          "renovation_cost": 43008,
                          "LP/FP": 147,
                          "pfs": 0,
                          "is_tlc": true,
                          "default_avm": 168941.12,
                          "avm": null,
                          "avm_low": null,
                          "avm_high": null,
                          "avm_confidence": null,
                          "avm_disagreement": null,
                          "total_financing_cost": 5760.3,
                          "total_holding_cost": 3798,
                          "total_loan_amount": 132930,
                          "total_project_cost": 69877.94,
                          "holding_cost": 949.5,
                          "interest": 3101.7,
                          "points": 2658.6,
                          "contingency": 1290.24,
                          "cost_at_purchase": 5697,
                          "cost_at_sale": 10324.4,
                          "downpayment": 56970,
                          "potential_roi": 84.69,
                          "weighted_pfs": 0,
                          "primary_photo": {
                            "href": "https://developers.homesage.ai/api/properties/image/<token>/"
                          },
                          "dom": 0
                        },
                        {
                          "address": {
                            "city": "Springfield",
                            "line": "1651 N Bristol Ave",
                            "postal_code": "65802",
                            "state": "Missouri",
                            "state_code": "MO",
                            "coordinate": {
                              "lat": 37.226371,
                              "lon": -93.204376
                            },
                            "street_direction": "N",
                            "street_name": "Bristol",
                            "street_number": "1651",
                            "street_post_direction": null,
                            "street_suffix": "Ave",
                            "unit": null,
                            "validation_code": "121"
                          },
                          "list_price": 736000,
                          "description": {
                            "baths": 3,
                            "baths_full": 3,
                            "baths_half": null,
                            "baths_consolidated": "3",
                            "beds": 4,
                            "garage": 3,
                            "garage_type": null,
                            "lot_sqft": 9583,
                            "sqft": 3381,
                            "stories": 2,
                            "type": "single_family",
                            "sub_type": null,
                            "year_built": 2022,
                            "name": null,
                            "construction": null,
                            "cooling": null,
                            "exterior": null,
                            "fireplace": null,
                            "heating": null,
                            "pool": null,
                            "roofing": null,
                            "rooms": null,
                            "styles": null,
                            "units": null,
                            "year_renovated": null,
                            "zoning": null
                          },
                          "status": "for_sale",
                          "last_update_date": "2026-06-08T11:05:32Z",
                          "neighborhood": null,
                          "final_property_condition": null,
                          "photo_analysis": null,
                          "condition_source": null,
                          "post_renovation_value": 758341.32,
                          "potential": 100,
                          "roi": 266.61,
                          "profit": 551487.93,
                          "renovation_cost": 84525,
                          "LP/FP": 97,
                          "pfs": 0,
                          "is_tlc": null,
                          "default_avm": 705203.04,
                          "avm": null,
                          "avm_low": null,
                          "avm_high": null,
                          "avm_confidence": null,
                          "avm_disagreement": null,
                          "total_financing_cost": 22325.33,
                          "total_holding_cost": 14720,
                          "total_loan_amount": 515200,
                          "total_project_cost": 206853.39,
                          "holding_cost": 3680,
                          "interest": 12021.33,
                          "points": 10304,
                          "contingency": 2535.75,
                          "cost_at_purchase": 22080,
                          "cost_at_sale": 60667.31,
                          "downpayment": 220800,
                          "potential_roi": 266.61,
                          "weighted_pfs": 0,
                          "primary_photo": {
                            "href": "https://developers.homesage.ai/api/properties/image/<token>/"
                          },
                          "dom": 0
                        }
                      ]
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream data provider is temporarily unavailable — retry with backoff."
          },
          "504": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": ""
          }
        },
        "x-slug": "bulk-info",
        "x-credits-unit": "property",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/bulk-info/?city=Springfield&state=MO&price_range_max=300000&page_size=20' \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nr = requests.get(\n    'https://developers.homesage.ai/api/properties/bulk-info/',\n    params={'city': 'Springfield', 'state': 'MO', 'price_range_max': 300000, 'page_size': 20},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nfor p in r.json()['properties']:\n    print(p['address'], p['potential_roi'])"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL('https://developers.homesage.ai/api/properties/bulk-info/');\nurl.searchParams.set('city', 'Springfield');\nurl.searchParams.set('state', 'MO');\nurl.searchParams.set('price_range_max', '300000');\nurl.searchParams.set('page_size', '20');\nconst r = await fetch(url, { headers: { Authorization: 'Token YOUR_API_KEY' } });"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/sold/by-zip/": {
      "get": {
        "operationId": "get_sold_properties_by_zip",
        "description": "\n## What it returns\n\nEvery residential property sold in a given US ZIP code within the last 365 days, with sale date, sale price, coordinates, and basic property characteristics (bed/bath, square footage, year built, lot size). Sourced from the `residential_sold` collection — a deduplicated rollup of MLS sold records refreshed on demand when the per-ZIP cache is older than 4 hours.\n\n## When to use it\n\n- Build a \"recent sales in my neighborhood\" widget on a property page.\n- Estimate market velocity for a ZIP code (sales per month, median DOM).\n- Seed a comps analysis without specifying individual subject properties.\n- Sanity-check listing prices against actual sale prices.\n\n## Date range\n\nBy default the endpoint returns the full trailing 365 days. Pass `start_date`, `end_date`, or both (`YYYY-MM-DD`) to narrow that to a specific window — for example one calendar month at a time instead of re-pulling the whole year on every poll:\n\n```\n?zip=95630&start_date=2026-08-01&end_date=2026-08-31\n```\n\nBoth bounds are optional and inclusive, and both are independent: pass only `start_date` for an open-ended window, or only `end_date` to cut off recent sales. Passing neither leaves existing behaviour unchanged.\n\nEither bound must fall within the last 365 days. An older date returns `400` naming the earliest date we can serve, rather than quietly returning a partial set.\n\n## Pricing\n\n**1 credit per 20 properties returned**, rounded up. A request that returns 100 properties costs 5 credits. Use the `limit` parameter to cap the cost — a `limit=20` always costs exactly 1 credit. Charged only on `200`; `402`/`400`/`5xx` cost nothing.\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | Missing `zip` parameter, non-integer `limit`, or a malformed / out-of-window `start_date` or `end_date`. |\n| 401 | Authentication failed or account missing. |\n| 402 | No subscription, or insufficient credits for the property count this ZIP would return. The error body includes the credit estimate so you can lower `limit` and retry. |\n| 503 | Upstream datastore or refresh error. Safe to retry. |\n\n## FAQ\n\n### How fresh is the data?\nThe per-ZIP cache refreshes when stale (older than 4 hours) on demand. A first request to a cold ZIP may take longer while the refresh runs; subsequent requests within the 4-hour window hit cache.\n\n### Why do some properties have `sold_price: null`?\nThe MLS suppresses price on private sales, off-market transfers, and some agent-sale records. The property still appears (it sold), but the price field is `null`. Filter on your side if you need price-bearing records only.\n\n### What counts as \"residential\"?\nSingle-family, condo, townhouse, and multi-family (2-4 unit) records. Commercial, land-only, and 5+ unit multi-family are excluded at the collection level — they live in different collections not exposed by this endpoint.\n\n### Why is `dom` sometimes `null`?\nDays-on-market requires listing-history dates that older records may not carry. For records that lack `dom` natively, we compute it best-effort from `list_date` to `sold_date`; when neither path resolves, the field is `null`.\n",
        "summary": "List residential properties sold in a ZIP in the last 365 days",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            },
            "description": "Cap the result count. When set, the response is the most recent N sales (after dedup + recency filter). Used to control credit cost — `limit=20` always costs 1 credit. Omit for the full last-365-days list.",
            "example": 10
          },
          {
            "in": "query",
            "name": "zip",
            "schema": {
              "type": "string"
            },
            "description": "5-digit US ZIP code. Example: `65802`.",
            "required": true,
            "example": "65802"
          },
          {
            "in": "query",
            "name": "start_date",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Earliest sale date to include, as `YYYY-MM-DD`. Optional — omit for the full 365-day window. Inclusive: a sale on this exact date is returned. Must fall within the last 365 days; anything older returns `400`, since that is the whole window we retain.",
            "example": "2026-08-01"
          },
          {
            "in": "query",
            "name": "end_date",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Latest sale date to include, as `YYYY-MM-DD`. Optional — omit for no upper bound. Inclusive: a sale on this exact date is returned. Must be on or after `start_date` and within the last 365 days.",
            "example": "2026-08-31"
          }
        ],
        "tags": ["Market Data"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SoldPropertyItem"
                  }
                },
                "examples": {
                  "ZIPWithOneRecentSale": {
                    "value": [
                      [
                        {
                          "property_address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                          "longitude": -93.201372,
                          "latitude": 37.227381,
                          "sold_date": "2026-04-12",
                          "sold_price": 285000,
                          "total_size": 1840,
                          "bedrooms": 3,
                          "bathrooms": 2.0,
                          "year_built": 2005,
                          "property_type": "single_family",
                          "stories": 1,
                          "parking": 2,
                          "lot_size": 8400,
                          "dom": 14
                        }
                      ]
                    ],
                    "summary": "ZIP with one recent sale"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream data provider is temporarily unavailable — retry with backoff."
          }
        },
        "x-slug": "sold-by-zip",
        "x-credits-unit": "20 properties",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/sold/by-zip/?zip=65802&limit=20' \\\n  -H 'Authorization: Token YOUR_API_KEY'\n\n# One calendar month instead of the full trailing year:\ncurl 'https://developers.homesage.ai/api/properties/sold/by-zip/?zip=65802&start_date=2026-08-01&end_date=2026-08-31' \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\n# Omit start_date/end_date for the full trailing 365 days.\nr = requests.get(\n    'https://developers.homesage.ai/api/properties/sold/by-zip/',\n    params={\n        'zip': '65802',\n        'start_date': '2026-08-01',\n        'end_date': '2026-08-31',\n    },\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nfor sold in r.json():\n    print(sold['property_address'], sold['sold_date'], sold['sold_price'])"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const url = new URL('https://developers.homesage.ai/api/properties/sold/by-zip/');\nurl.searchParams.set('zip', '65802');\n// Optional: narrow to a single month.\nurl.searchParams.set('start_date', '2026-08-01');\nurl.searchParams.set('end_date', '2026-08-31');\nconst r = await fetch(url, {\n  headers: { Authorization: 'Token YOUR_API_KEY' },\n});\nconst sold: SoldProperty[] = await r.json();"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/sold/count-by-zip/": {
      "get": {
        "operationId": "get_sold_count_by_zip",
        "description": "## What it returns\n\nJust the **count** of residential properties sold in a ZIP within the last 365 days. Same dedup + recency rules as `sold-by-zip`, but only the integer count — useful when you don't need the property details and want to minimize cost.\n\n## When to use it\n\n- Display market velocity in a header widget (no need to render rows).\n- Drive a chart of monthly sales trend across many ZIPs cheaply.\n- Pre-check whether a ZIP has enough comp activity before calling `sold-by-zip`.\n\n## Date range\n\nBy default the endpoint returns the full trailing 365 days. Pass `start_date`, `end_date`, or both (`YYYY-MM-DD`) to narrow that to a specific window — for example one calendar month at a time instead of re-pulling the whole year on every poll:\n\n```\n?zip=95630&start_date=2026-08-01&end_date=2026-08-31\n```\n\nBoth bounds are optional and inclusive, and both are independent: pass only `start_date` for an open-ended window, or only `end_date` to cut off recent sales. Passing neither leaves existing behaviour unchanged.\n\nEither bound must fall within the last 365 days. An older date returns `400` naming the earliest date we can serve, rather than quietly returning a partial set.\n\n## Pricing\n\n1 credit per call regardless of the count.\n\n## FAQ\n\n### What's the difference between this and `sold-by-zip`?\nThis returns one integer (1 credit). `sold-by-zip` returns the full list (1 credit per 20 properties). Use this for cost-efficient screening; use `sold-by-zip` when you need details.",
        "summary": "Count of sold properties in a ZIP in the last 365 days",
        "parameters": [
          {
            "in": "query",
            "name": "zip",
            "schema": {
              "type": "string"
            },
            "description": "5-digit US ZIP code.",
            "required": true,
            "example": "65802"
          },
          {
            "in": "query",
            "name": "start_date",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Earliest sale date to include, as `YYYY-MM-DD`. Optional — omit for the full 365-day window. Inclusive: a sale on this exact date is returned. Must fall within the last 365 days; anything older returns `400`, since that is the whole window we retain.",
            "example": "2026-08-01"
          },
          {
            "in": "query",
            "name": "end_date",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Latest sale date to include, as `YYYY-MM-DD`. Optional — omit for no upper bound. Inclusive: a sale on this exact date is returned. Must be on or after `start_date` and within the last 365 days.",
            "example": "2026-08-31"
          }
        ],
        "tags": ["Market Data"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "zip_code": "65802",
                      "count": 986
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream data provider is temporarily unavailable — retry with backoff."
          }
        },
        "x-slug": "sold-count-by-zip",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/sold/count-by-zip/?zip=65802' \\\n  -H 'Authorization: Token YOUR_API_KEY'\n\n# Same date range as sold/by-zip, so the count always describes the list:\ncurl 'https://developers.homesage.ai/api/properties/sold/count-by-zip/?zip=65802&start_date=2026-08-01&end_date=2026-08-31' \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/sold/count-by-zip/', params={'zip': '65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/current-estimate/": {
      "get": {
        "operationId": "get_current_estimate",
        "description": "## What it returns\n\nThe current Homesage.ai AVM (Automated Valuation Model) estimate for a US residential property — a single point estimate: the current estimated value (`current_value`), returned inside an `Estimates` object. Sourced from Homesage.ai's first-party AVM service.\n\n## When to use it\n\n- Set a listing price for a property about to go on the market.\n- Cross-check against a third-party AVM.\n- Trigger an alert when AVM moves beyond a threshold.\n\n## Pricing\n\n**2 credits per successful call.** `404`/`401`/`402` cost 0 credits.\n\n## FAQ\n\n### Why does the AVM disagree with other estimates?\nDifferent models, different training data, different feature weights. Homesage.ai emphasizes recent comparable sales + condition signals; other estimates may emphasize a broader market-trend model. Neither is right or wrong — they answer slightly different questions.\n\n### How fresh is the estimate?\nRecomputed when the underlying property record refreshes (cache TTL ~24h).",
        "summary": "Homesage.ai AVM (current estimated value) for a property",
        "parameters": [
          {
            "in": "query",
            "name": "property_address",
            "schema": {
              "type": "string"
            },
            "description": "Full address. Example: `4411 E Hidden Oak St Springfield MO 65802`.",
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Property Valuation"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "address": "4411 E Hidden Oak St Springfield MO 65802",
                      "Estimates": {
                        "current_value": 583410.33
                      }
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream data provider is temporarily unavailable — retry with backoff."
          }
        },
        "x-slug": "current-estimate",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/current-estimate/?property_address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/current-estimate/', params={'property_address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})\nprint(r.json())"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 2
      }
    },
    "/api/properties/renovation-cost-breakdown/": {
      "post": {
        "operationId": "advanced_renovation_cost_breakdown",
        "description": "## What it returns\n\nAn itemized **room-by-room renovation cost breakdown** powered by a multimodal LLM analyzing the property's images plus its size/feature metadata. Returns per-room scope, material/labor split, and total cost — significantly more detailed than the top-level `renovation-cost` aggregate.\n\n## When to use it\n\n- Generate detailed scope-of-work documents from photos.\n- Underwrite specific renovation strategies.\n- Show investor clients exactly where the money goes.\n\n## Pricing\n\n5 credits.\n\n## Request\n\nSend a JSON body. Provide either `property_id` (we'll pull images and metadata for it), `property_address` (we'll resolve it), or the full `property` object plus an `images` array of URLs.\n\n## FAQ\n\n### Can I force a fresh LLM analysis (bypass cache)?\nYes — set `force_refresh: true` in the request body. Bypasses the per-property cache.\n\n### What LLM is used?\nA multimodal model tuned for construction-cost estimation. Outputs are in domain terms (rooms, materials, line-items) and stable across model swaps.",
        "summary": "LLM-powered room-by-room renovation cost breakdown",
        "tags": ["AI-Powered Analysis"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address; the backend resolves the property images + metadata server-side."
                  }
                }
              },
              "examples": {
                "EstimateByAddress": {
                  "value": {
                    "property_address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                  },
                  "summary": "Estimate by address"
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address; the backend resolves the property images + metadata server-side."
                  }
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address; the backend resolves the property images + metadata server-side."
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "property_summary": {
                        "address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                        "total_sqft": 2351,
                        "bedrooms": 3,
                        "bathrooms": 2,
                        "overall_condition_score": 10,
                        "overall_condition_category": "Excellent",
                        "renovation_cost_min": 64735,
                        "renovation_cost_max": 94160,
                        "renovation_cost_estimate": 79447.5,
                        "confidence_score": 95,
                        "major_red_flags": [
                          "Steep lot grading: The property is situated on a significant slope which may require ongoing monitoring for erosion control and proper drainage management to protect the foundation."
                        ],
                        "non_visible_areas_included": true,
                        "estimation_notes": "Property is a 2024 new construction in pristine condition. Interior and exterior finishes are modern and high-end. Costs are primarily allocated to finishing the walk-out basement (inferred from exterior slope and foundation height) and a standard new-construction punch list for final detailing."
                      },
                      "rooms": [
                        {
                          "room_id": "kitchen_01",
                          "room_type": "Kitchen",
                          "estimated_not_photographed": false,
                          "visual_condition_notes": "Pristine new construction. Quartz countertops, shaker cabinets, stainless steel appliances, and subway tile backsplash.",
                          "dimensions_estimated": "15x18",
                          "room_condition_score": 10,
                          "room_condition_category": "Excellent",
                          "elements": [
                            {
                              "element_name": "Cabinetry and Counters",
                              "current_material": "Painted Shaker / Quartz",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "None - Punch list detailing only",
                              "quantity_estimated": "1 unit",
                              "unit_price_assumption": "$500 flat for hardware adjustment and cleaning",
                              "cost_low": 400,
                              "cost_high": 600,
                              "priority": "Low"
                            },
                            {
                              "element_name": "Appliances",
                              "current_material": "Stainless Steel",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "Calibration and testing",
                              "quantity_estimated": "1 set",
                              "unit_price_assumption": "$250 for professional commissioning",
                              "cost_low": 200,
                              "cost_high": 300,
                              "priority": "Low"
                            }
                          ],
                          "room_total_low": 600,
                          "room_total_high": 900
                        },
                        {
                          "room_id": "living_dining_combo",
                          "room_type": "Living Room",
                          "estimated_not_photographed": false,
                          "visual_condition_notes": "Open concept with hardwood floors, fireplace with accent wall, and high ceilings. Excellent condition.",
                          "dimensions_estimated": "25x20",
                          "room_condition_score": 10,
                          "room_condition_category": "Excellent",
                          "elements": [
                            {
                              "element_name": "Flooring",
                              "current_material": "Engineered Hardwood",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "Deep clean and protection",
                              "quantity_estimated": "500 sqft",
                              "unit_price_assumption": "$1.50/sqft for professional cleaning/sealing",
                              "cost_low": 600,
                              "cost_high": 900,
                              "priority": "Low"
                            },
                            {
                              "element_name": "Walls and Trim",
                              "current_material": "Drywall / Wood Trim",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "Minor paint touch-ups",
                              "quantity_estimated": "1200 sqft surface",
                              "unit_price_assumption": "$0.75/sqft for labor touch-ups",
                              "cost_low": 700,
                              "cost_high": 1100,
                              "priority": "Low"
                            }
                          ],
                          "room_total_low": 1300,
                          "room_total_high": 2000
                        }
                      ],
                      "non_visible_areas": [
                        {
                          "area_type": "Basement (Unfinished)",
                          "reasoning": "Exterior photos show a walk-out foundation level. Instruction #7 requires including costs for finishing unfinished areas.",
                          "estimated_not_photographed": true,
                          "dimensions_estimated": "Approx 1200 sqft",
                          "condition_score": 5,
                          "condition_category": "Outdated",
                          "elements": [
                            {
                              "element_name": "Basement Build-out",
                              "current_material": "Concrete/Studs",
                              "condition_score": 5,
                              "condition_category": "Outdated",
                              "action_required": "Full finish (Drywall, Flooring, Electrical, HVAC extension)",
                              "quantity_estimated": "1200 sqft",
                              "unit_price_assumption": "$40/sqft for mid-range finish",
                              "cost_low": 45000,
                              "cost_high": 65000,
                              "priority": "Medium"
                            }
                          ],
                          "area_total_low": 45000,
                          "area_total_high": 65000
                        },
                        {
                          "area_type": "Garage",
                          "reasoning": "3-car garage visible from exterior but not interior.",
                          "estimated_not_photographed": true,
                          "dimensions_estimated": "Approx 650 sqft",
                          "condition_score": 10,
                          "condition_category": "Excellent",
                          "elements": [
                            {
                              "element_name": "Floor Coating",
                              "current_material": "Concrete",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "Epoxy coating (Optional upgrade)",
                              "quantity_estimated": "650 sqft",
                              "unit_price_assumption": "$5.00/sqft",
                              "cost_low": 3000,
                              "cost_high": 3500,
                              "priority": "Low"
                            }
                          ],
                          "area_total_low": 3000,
                          "area_total_high": 3500
                        }
                      ],
                      "systems_and_exterior": [
                        {
                          "system_type": "HVAC/Plumbing/Electrical",
                          "estimated_not_photographed": true,
                          "condition_score": 10,
                          "condition_category": "Excellent",
                          "elements": [
                            {
                              "element_name": "System Commissioning",
                              "current_material": "Modern 2024 Systems",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "Final inspections and testing",
                              "quantity_estimated": "1 unit",
                              "unit_price_assumption": "$1000 allowance",
                              "cost_low": 800,
                              "cost_high": 1200,
                              "priority": "Low"
                            }
                          ],
                          "system_total_low": 800,
                          "system_total_high": 1200
                        },
                        {
                          "system_type": "Exterior and Landscaping",
                          "estimated_not_photographed": false,
                          "condition_score": 10,
                          "condition_category": "Excellent",
                          "elements": [
                            {
                              "element_name": "Landscaping and Deck",
                              "current_material": "Brick/Stone/Wood",
                              "condition_score": 10,
                              "condition_category": "Excellent",
                              "action_required": "Final grading touch-ups and deck staining",
                              "quantity_estimated": "1 unit",
                              "unit_price_assumption": "$2500 allowance",
                              "cost_low": 2000,
                              "cost_high": 3000,
                              "priority": "Medium"
                            }
                          ],
                          "system_total_low": 2000,
                          "system_total_high": 3000
                        }
                      ],
                      "additional_costs": {
                        "miscellaneous": {
                          "description": "Permits, inspections, debris removal, dumpster rental, small unforeseen items, equipment rental",
                          "percentage_applied": 7,
                          "calculation_basis": "Percentage of all direct renovation costs",
                          "cost_low": 3850,
                          "cost_high": 5600
                        },
                        "contingency": {
                          "description": "Unforeseen conditions, hidden damage, scope changes, material price fluctuations",
                          "percentage_applied": 10,
                          "calculation_basis": "Percentage of (all direct costs + miscellaneous)",
                          "cost_low": 5885,
                          "cost_high": 8560,
                          "reasoning": "10% contingency applied. While the property is new, the significant basement finish scope warrants a standard contingency for material fluctuations."
                        }
                      },
                      "cost_breakdown_summary": {
                        "direct_renovation_costs_low": 55000,
                        "direct_renovation_costs_high": 80000,
                        "miscellaneous_low": 3850,
                        "miscellaneous_high": 5600,
                        "contingency_low": 5885,
                        "contingency_high": 8560,
                        "grand_total_low": 64735,
                        "grand_total_high": 94160
                      }
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressLookupError"
                }
              }
            },
            "description": "Not found — the address could not be confidently matched to a single property. The body includes a `did_you_mean` array of suggested addresses (each with an `mpr_id`) to show the user and retry with; an empty array means no close match. Costs 0 credits."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": ""
          }
        },
        "x-slug": "renovation-cost-breakdown",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://developers.homesage.ai/api/properties/renovation-cost-breakdown/' \\\n  -H 'Authorization: Token YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"property\": {\"address\": \"4411 E Hidden Oak St Springfield MO 65802\", \"total_sqft\": 1840, \"bedrooms\": 3, \"bathrooms\": 2.0}, \"images\": [\"https://...\"]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.post(\n    'https://developers.homesage.ai/api/properties/renovation-cost-breakdown/',\n    json={'property': {'address': '4411 E Hidden Oak St Springfield MO 65802', 'total_sqft': 1840, 'bedrooms': 3, 'bathrooms': 2.0}, 'images': ['https://...']},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 5
      }
    },
    "/api/properties/skip-tracing/property-owner-information/": {
      "post": {
        "operationId": "skip_trace_property_owner",
        "description": "## What it returns\n\nThe **legal owner** of a US residential property given its address — name, mailing address (if different from the property), and contact methods (email and phone with connectivity/verification flags). Built from county records + skip-trace providers.\n\n## When to use it\n\n- Direct-mail and cold-outreach campaigns for real-estate investors.\n- Owner verification before drafting an offer.\n- CRM enrichment by property address.\n\n## Pricing\n\n4 credits per address resolved.\n\n## FAQ\n\n### How fresh is the data?\nUpstream providers refresh on their own cadence. Treat data older than 12 months as stale for high-stakes outreach.\n\n### Does this work for commercial properties?\nLimited. Residential is the primary use case.\n\n### What's the difference between this and `associated-people`?\nThis returns the *legal owner* (one or two persons). `associated-people` returns everyone the address can be linked to (residents, relatives, prior owners).",
        "summary": "Property owner name + contact info from an address",
        "tags": ["Skip Tracing"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to skip-trace for owner information."
                  }
                }
              },
              "examples": {
                "LookUpByAddress": {
                  "value": {
                    "property_address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                  },
                  "summary": "Look up by address"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to skip-trace for owner information."
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to skip-trace for owner information."
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "persons": [
                        {
                          "propertyAddress": {
                            "addressValidity": "Valid",
                            "hash": "d12c61d416d7a2de3d0da53c19ce87ad",
                            "street": "4411 E Hidden Oak St",
                            "city": "Springfield",
                            "state": "MO",
                            "zip": "65802",
                            "zipPlus4": "3678",
                            "houseNumber": "4411",
                            "county": "Greene",
                            "streetNoUnit": "4411 E Hidden Oak St",
                            "formattedStreet": "E Hidden Oak St",
                            "deliveryPointCode": "113",
                            "dpvMatchCode": "Y",
                            "dpvFootnotes": "AABB"
                          },
                          "name": {
                            "first": "George",
                            "last": "Kromrey",
                            "middle": "Bernard",
                            "full": "George Bernard Kromrey"
                          },
                          "phoneNumbers": [
                            {
                              "number": "5732599903",
                              "type": "Mobile",
                              "carrier": "NEW CINGULAR WIRELESS PCS- LLC - IL",
                              "tested": true,
                              "reachable": true,
                              "dnc": true,
                              "lastReportedDate": "2026-05-29T00:00:00.000Z",
                              "score": 100
                            },
                            {
                              "number": "5732599913",
                              "type": "Mobile",
                              "carrier": "NEW CINGULAR WIRELESS PCS- LLC - IL",
                              "tested": true,
                              "reachable": true,
                              "dnc": true,
                              "lastReportedDate": "2026-05-29T00:00:00.000Z",
                              "score": 95
                            }
                          ],
                          "emails": [
                            {
                              "email": "gkromrey@yahoo.com",
                              "tested": false
                            },
                            {
                              "email": "dkromrey@netscape.net",
                              "tested": false
                            }
                          ],
                          "mailingAddress": {
                            "addressValidity": "Valid",
                            "hash": "52af56e6e0c30a08de8a1cf7a37796c8",
                            "street": "21657 Avon Park Ct",
                            "city": "Venice",
                            "state": "FL",
                            "zip": "34293",
                            "zipPlus4": "2381",
                            "houseNumber": "21657",
                            "county": "Sarasota",
                            "streetNoUnit": "21657 Avon Park Ct",
                            "formattedStreet": "Avon Park Ct",
                            "deliveryPointCode": "573",
                            "dpvMatchCode": null,
                            "dpvFootnotes": null
                          },
                          "property": {
                            "address": {
                              "addressValidity": "Valid",
                              "hash": "d12c61d416d7a2de3d0da53c19ce87ad",
                              "street": "4411 E Hidden Oak St",
                              "city": "Springfield",
                              "state": "MO",
                              "zip": "65802",
                              "zipPlus4": "3678",
                              "houseNumber": "4411",
                              "county": "Greene",
                              "streetNoUnit": "4411 E Hidden Oak St",
                              "formattedStreet": "E Hidden Oak St",
                              "deliveryPointCode": "113",
                              "dpvMatchCode": "Y",
                              "dpvFootnotes": "AABB"
                            },
                            "owner": {
                              "name": {
                                "first": "George",
                                "last": "Kromrey",
                                "middle": null,
                                "full": "George Kromrey"
                              },
                              "mailingAddress": {
                                "addressValidity": "Valid",
                                "hash": "d12c61d416d7a2de3d0da53c19ce87ad",
                                "street": "4411 E Hidden Oak St",
                                "city": "Springfield",
                                "state": "MO",
                                "zip": "65802",
                                "zipPlus4": "3678",
                                "houseNumber": "4411",
                                "county": "Greene",
                                "streetNoUnit": "4411 E Hidden Oak St",
                                "formattedStreet": "E Hidden Oak St",
                                "deliveryPointCode": "113",
                                "dpvMatchCode": "Y",
                                "dpvFootnotes": "AABB"
                              }
                            }
                          },
                          "death": {
                            "deceased": false
                          },
                          "dnc": {
                            "tcpa": false
                          },
                          "litigator": false,
                          "meta": {
                            "matched": true,
                            "error": false
                          }
                        }
                      ],
                      "count": 1,
                      "summary": {
                        "requestCount": 1,
                        "matchCount": 1,
                        "noMatchCount": 0,
                        "errorCount": 0
                      },
                      "credits_charged": true
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Not found — the address or identifier did not resolve to a record. Costs 0 credits."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": ""
          }
        },
        "x-slug": "property-owner",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://developers.homesage.ai/api/properties/skip-tracing/property-owner-information/' \\\n  -H 'Authorization: Token YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.post(\n    'https://developers.homesage.ai/api/properties/skip-tracing/property-owner-information/',\n    json={'address': '4411 E Hidden Oak St, Springfield, MO, 65802'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 4
      }
    },
    "/api/properties/skip-tracing/associated-people/": {
      "post": {
        "operationId": "skip_trace_associated_people",
        "description": "## What it returns\n\nA list of **people associated** with a property address — historical residents, current and former owners, related family members. Each person carries a `person_id` you can pass to `skip-tracing/person-details` for a full dossier.\n\n## When to use it\n\n- Build outreach lists beyond just the legal owner (e.g. family members of a deceased owner).\n- Discover hidden parties to a property (trust beneficiaries, relatives).\n\n## Pricing\n\n1 credit per call.\n\n## FAQ\n\n### What's the difference vs. `property-owner`?\nThis returns the broader set (everyone linked to the address), at the cost of less identity detail per person. Use `property-owner` for the legal owner; `associated-people` for the wider net; `person-details` for the deep dive on a specific person.",
        "summary": "People associated with a property address (residents, relatives)",
        "tags": ["Skip Tracing"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to skip-trace for associated people."
                  }
                }
              },
              "examples": {
                "LookUpByAddress": {
                  "value": {
                    "property_address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                  },
                  "summary": "Look up by address"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to skip-trace for associated people."
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["property_address"],
                "properties": {
                  "property_address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to skip-trace for associated people."
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "people": [
                        {
                          "Name": "Sandra Kromrey",
                          "Age": 73,
                          "Lives in": "Springfield, MO",
                          "Used to live in": "Venice FL, Arlington Heights IL, Sullivan...",
                          "Related to": "David Kromrey, George Kromrey, Loryn Kromr...",
                          "Person ID": "px608nl9l0l242nl89nu2"
                        },
                        {
                          "Name": "George Kromrey",
                          "Age": 74,
                          "Lives in": "Venice, FL",
                          "Used to live in": "Arlington Heights IL, Springfield MO, Sul...",
                          "Related to": "David Kromrey, Loryn Kromrey, Loryn Kromre...",
                          "Person ID": "p6uul42ln899nu924u0r"
                        }
                      ],
                      "total_records": 2,
                      "page": 1,
                      "credits_charged": true
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Not found — the address or identifier did not resolve to a record. Costs 0 credits."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": ""
          }
        },
        "x-slug": "associated-people",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://developers.homesage.ai/api/properties/skip-tracing/associated-people/' \\\n  -H 'Authorization: Token YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.post(\n    'https://developers.homesage.ai/api/properties/skip-tracing/associated-people/',\n    json={'address': '4411 E Hidden Oak St, Springfield, MO, 65802'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/skip-tracing/person-details/": {
      "post": {
        "operationId": "skip_trace_person_details",
        "description": "\n## What it returns\n\nFull skip-trace dossier for a single person — current and previous addresses, phone numbers (with type and connectivity status), email addresses (with verification status), relatives, and associates. The `person_id` input must come from a prior call to `skip-tracing/associated-people` — this endpoint does not accept free-form name lookup.\n\n## When to use it\n\n- You have a `person_id` from `associated-people` and want full contact details before reaching out.\n- You're enriching a CRM record with verified phones/emails for a known person.\n- You need historical address data to verify identity or reconstruct timelines.\n\n## Pricing\n\n**1 credit per call.** A first call for a given `person_id` hits the upstream provider; subsequent calls within the per-user history cache are free. Identical calls from other accounts hit a shared global cache but still cost 1 credit (the data has value; the speed is the gift).\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 400 | Missing `person_id` field, or `person_id` not recognized by the provider. |\n| 401 | Authentication failed. |\n| 402 | Insufficient credits. |\n| 502 | Upstream skip-tracing microservice unavailable. Safe to retry with exponential backoff. |\n\n## FAQ\n\n### How fresh is the data?\nThe upstream provider refreshes records on its own cadence; we don't control it. For privacy-sensitive use cases, treat addresses older than 12 months as stale.\n\n### What's the difference between this and `skip-tracing/associated-people`?\n`associated-people` returns a list of people tied to a property address with minimal detail per person (name, relationship inference, `person_id`). This endpoint takes one of those `person_id`s and returns the full dossier for that one person. Use them together: list → drill down.\n\n### Why might `current_addresses` be empty?\nThe provider has no current-address record for the person. This is common for transient or recently deceased individuals.\n\n### Is the data court-admissible?\nNo. Skip-trace data is research-grade aggregation of public records and is not certified for legal proceedings.\n",
        "summary": "Full skip-trace dossier for a known person_id",
        "tags": ["Skip Tracing"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SkipTracePersonDetailsRequestRequest"
              },
              "examples": {
                "LookupByPersonId": {
                  "value": {
                    "person_id": "p4r4020l80998ll84l64"
                  },
                  "summary": "Lookup by person_id"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/SkipTracePersonDetailsRequestRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/SkipTracePersonDetailsRequestRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkipTracePersonDetailsResponse"
                },
                "examples": {
                  "PersonWithTwoCurrentAddressesAndAVerifiedEmail": {
                    "value": {
                      "person_details": [
                        {
                          "first_name": "Jane",
                          "last_name": "Doe",
                          "age": 47,
                          "date_of_birth": "1978-04-12"
                        }
                      ],
                      "current_addresses": [
                        {
                          "address": "4411 E Hidden Oak St",
                          "city": "Springfield",
                          "state": "MO",
                          "zip": "65802",
                          "type": "current",
                          "first_seen": "2022-08-01",
                          "last_seen": "2026-05-20"
                        }
                      ],
                      "phone_numbers": [
                        {
                          "number": "+14175551234",
                          "type": "mobile",
                          "is_connected": true
                        }
                      ],
                      "email_addresses": [
                        {
                          "address": "jane.doe@example.com",
                          "is_verified": true
                        }
                      ],
                      "previous_addresses": [],
                      "relatives": [],
                      "associates": []
                    },
                    "summary": "Person with two current addresses and a verified email"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "description": "No response body"
          },
          "401": {
            "description": "No response body"
          },
          "402": {
            "description": "No response body"
          },
          "502": {
            "description": "No response body"
          }
        },
        "x-slug": "person-details",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl https://developers.homesage.ai/api/properties/skip-tracing/person-details/ \\\n  -X POST \\\n  -H 'Authorization: Token YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"person_id\": \"p4r4020l80998ll84l64\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nr = requests.post(\n    'https://developers.homesage.ai/api/properties/skip-tracing/person-details/',\n    json={'person_id': 'p4r4020l80998ll84l64'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nfor phone in r.json()['phone_numbers']:\n    print(phone['number'], phone.get('is_connected'))"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const r = await fetch('https://developers.homesage.ai/api/properties/skip-tracing/person-details/', {\n  method: 'POST',\n  headers: {\n    Authorization: 'Token YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ person_id: 'p4r4020l80998ll84l64' }),\n});\nconst dossier = await r.json();"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 1
      }
    },
    "/api/properties/market-outlook/": {
      "get": {
        "operationId": "get_market_outlook",
        "description": "## What it returns\n\nA composite **Market Outlook score** (0-100) classifying a ZIP code as a buyer's market (<40), balanced (40-60), or seller's market (>60). Built from a hybrid weighted model — 40% macro market indicators (market-heat index and forecasts), 40% Homesage.ai absorption-rate analytics, and 20% live market signals when available. Includes 1/3/6-month forecasts, days-on-market velocity, active/sold/pending counts, and a per-signal breakdown.\n\n## When to use it\n\n- Render a market-context widget on a property report.\n- Power a 'best markets to buy' / 'best markets to sell' ranking.\n- Inform pricing-strategy recommendations.\n\n## Pricing\n\n2 credits.\n\n## FAQ\n\n### What if live market data is unavailable?\nThe live-signal weight rebalances to the macro and Homesage.ai components (50% / 50%). The response's `weights_used` field reflects the actual weights applied.\n\n### Why ZIP-level instead of city or county?\nZIP is the smallest unit that all three sources support consistently. For city/county roll-ups, query multiple ZIPs and aggregate.",
        "summary": "Local market outlook (buyer's/balanced/seller's) for a ZIP",
        "parameters": [
          {
            "in": "query",
            "name": "days",
            "schema": {
              "type": "integer"
            },
            "description": "Lookback window. Default 90 days.",
            "example": 30
          },
          {
            "in": "query",
            "name": "zip",
            "schema": {
              "type": "string"
            },
            "description": "5-digit US ZIP code.",
            "required": true,
            "example": "65802"
          }
        ],
        "tags": ["AI-Powered Analysis"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "zip_code": "65802",
                      "metro_name": "Springfield, MO",
                      "timestamp": "2026-06-08T21:15:08.043725",
                      "weights_used": {
                        "metro_index": 0.5,
                        "local_transactions": 0.5,
                        "metro_status": 0
                      },
                      "outlook_score": {
                        "value": 70.7,
                        "label": "Seller's Market",
                        "color_code": "#FF4500"
                      },
                      "forecast_bars": [
                        {
                          "label": "1 Month",
                          "percentage": 0.2,
                          "trend": "up",
                          "heat_index": 41.39842105263158
                        },
                        {
                          "label": "3 Months",
                          "percentage": 0.8,
                          "trend": "up",
                          "heat_index": 41.64631578947369
                        }
                      ],
                      "market_velocity": {
                        "avg_days_on_market_metro": 65,
                        "local_absorption_rate": 257.69,
                        "pfs_score": null
                      },
                      "micro_stats": {
                        "active_count": 208,
                        "sold_count_90d": 536,
                        "pending_count_90d": 0,
                        "absorption_rate_pct": 257.69
                      },
                      "source_breakdown": {
                        "metro_index": {
                          "score": 41.31578947368421,
                          "market_temperature": 47,
                          "metro_name": "Springfield, MO",
                          "available": true,
                          "data_date": "2026-02-28 00:00:00"
                        },
                        "local_transactions": {
                          "score": 100,
                          "absorption_rate": 257.69,
                          "active_count": 208,
                          "sold_count": 536,
                          "pending_count": 0,
                          "available": true
                        },
                        "metro_status": {
                          "score": null,
                          "market_status": null,
                          "available": false,
                          "cached": false
                        }
                      },
                      "credits_charged": 2
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream data provider is temporarily unavailable — retry with backoff."
          }
        },
        "x-slug": "market-outlook",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/properties/market-outlook/?zip=65802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/properties/market-outlook/', params={'zip': '65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 2
      }
    },
    "/api/properties/red-flags/stream/": {
      "post": {
        "operationId": "location_red_flags_stream",
        "description": "## What it returns\n\nA **Server-Sent Events stream** of location-risk findings for a US property — flood, crime, environmental hazards, school-district decline, and other neighborhood red flags. Emits five sequential events:\n\n1. `geocoded` — the address has been resolved to coordinates\n2. `area_classified` — neighborhood + ZIP context loaded\n3. `flags_detected` — text-based risk lookup complete\n4. `vision_analyzed` — aerial-imagery analysis complete\n5. `complete` — final report with aggregated findings\n\nPlus `error` if any stage fails. The `complete` event is augmented with `from_cache: true` + `cached_at` (ISO 8601 UTC, `Z` suffix) when served from cache.\n\n## When to use it\n\n- Render a real-time risk-analysis page where each stage animates as it loads.\n- Pre-screen wholesale leads for hidden risk factors before outreach.\n- Disclose neighborhood risk to buyers in a transparent format.\n\n## Pricing\n\n5 credits per fresh request. Cache hits (re-running the same `address`+`detection_mode` for the same user within the cache TTL) cost 0 credits and replay the full event sequence so client UIs animate identically.\n\n## Streaming protocol\n\nContent-Type: `text/event-stream`. Each event follows the SSE spec — `event: <name>` newline, `data: <json>` newline, blank-line separator. Errors return as `event: error`; errored runs are never persisted to cache.\n\n## FAQ\n\n### What if I don't want streaming?\nThe endpoint is streaming-only. Consume the full stream and use the `complete` event's payload as the final response.\n\n### Why is `detection_mode` not a parameter?\nThe proxy forces `detection_mode: single` and ignores client-supplied values. Multi-mode is reserved for future expansion.\n\n### How long do cached results live?\nUntil the cache TTL expires. Stale rows are self-purged on next lookup — no scheduled task. Cache key is per-user + sha256(normalized address).",
        "summary": "Streaming location-risk analysis for a US address",
        "tags": ["Risk & Diligence"],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Full US property address to scan for location-based red flags.",
                    "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
                  }
                },
                "required": ["address"]
              },
              "examples": {
                "StreamRedFlagsForAnAddress": {
                  "value": {
                    "address": "4411 E Hidden Oak St, Springfield, MO, 65802"
                  },
                  "summary": "Stream red flags for an address"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "additionalProperties": {}
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "additionalProperties": {}
              }
            }
          }
        },
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": ""
          }
        },
        "x-slug": "location-red-flags",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -N -X POST 'https://developers.homesage.ai/api/properties/red-flags/stream/' \\\n  -H 'Authorization: Token YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"address\": \"4411 E Hidden Oak St, Springfield, MO, 65802\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nwith requests.post(\n    'https://developers.homesage.ai/api/properties/red-flags/stream/',\n    json={'address': '4411 E Hidden Oak St, Springfield, MO, 65802'},\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n    stream=True,\n) as r:\n    for line in r.iter_lines():\n        if line:\n            print(line.decode())"
          }
        ],
        "x-playground": "confirm",
        "x-drift-target": "cassette",
        "x-credits": 5
      }
    },
    "/api/usage/credits/": {
      "get": {
        "operationId": "get_credit_balance",
        "description": "\n## What it returns\n\nYour account's current API credit balance plus the plan and billing context that puts the number in context — `credits_used`, `credits_remaining`, `total_credits`, `usage_percentage`, current `plan_name` and `subscription_status`, and the `renewal_date` when the allowance resets. Sourced from your subscription record and live credit-usage counters; no third-party data providers involved.\n\n## When to use it\n\n- Display the user's remaining credits in your dashboard.\n- Poll before a batch job to check headroom — calls are free (`0` credits).\n- Surface `subscription_status` to gate paid features in your UI.\n- Compare `renewal_date` to \"now\" to show countdown timers.\n\n## Pricing\n\nFree. This endpoint costs **0 credits** per call. Safe to poll on every page load.\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| 401 | Missing or invalid API key. |\n| 403 | API key valid but account is suspended. |\n\n## FAQ\n\n### Why is `credits_remaining` `null`?\nYour plan is unlimited or a custom plan with no fixed per-period cap. The other balance fields are also `null` in that case. `credits_used` is always populated.\n\n### When does the balance reset?\nAt `renewal_date`. For monthly plans, that's the Stripe billing-period end. For yearly plans, the credit allowance resets monthly even though the subscription itself renews yearly — `renewal_date` is the next monthly reset, not the yearly one.\n\n### What if the user has no subscription at all?\n`plan_name`, `total_credits`, and most other fields are `null`. `credits_used` is still populated (any credits consumed outside a subscription period are reported). `subscription_status` is an empty string.\n",
        "summary": "Get the account's current API credit balance",
        "tags": ["Account"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalanceResponse"
                },
                "examples": {
                  "ActiveMonthlyPlan,250Of500CreditsUsed": {
                    "value": {
                      "credits_remaining": 250,
                      "credits_used": 250,
                      "total_credits": 500,
                      "usage_percentage": 50.0,
                      "plan_name": "Professional",
                      "subscription_status": "active",
                      "renewal_date": "2026-07-01T00:00:00+00:00",
                      "billing_period_start": "2026-06-01T00:00:00+00:00"
                    },
                    "summary": "Active monthly plan, 250 of 500 credits used"
                  },
                  "UnlimitedPlan": {
                    "value": {
                      "credits_remaining": null,
                      "credits_used": 1273,
                      "total_credits": null,
                      "usage_percentage": null,
                      "plan_name": "Enterprise Unlimited",
                      "subscription_status": "active",
                      "renewal_date": "2027-01-01T00:00:00+00:00",
                      "billing_period_start": "2026-01-01T00:00:00+00:00"
                    },
                    "summary": "Unlimited plan"
                  }
                }
              }
            },
            "description": ""
          }
        },
        "x-slug": "credit-balance",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl https://developers.homesage.ai/api/usage/credits/ \\\n  -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nr = requests.get(\n    'https://developers.homesage.ai/api/usage/credits/',\n    headers={'Authorization': 'Token YOUR_API_KEY'},\n)\nprint(r.json()['credits_remaining'])"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const r = await fetch('https://developers.homesage.ai/api/usage/credits/', {\n  headers: { Authorization: 'Token YOUR_API_KEY' },\n});\nconst { credits_remaining } = await r.json();"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "django",
        "x-credits": 0
      }
    },
    "/api/solar/analysis/": {
      "get": {
        "operationId": "get_solar_analysis",
        "description": "## What it returns\n\nTwo coupled analyses in one call:\n\n1. **Solar Potential** — 20-year cost projection, payback timeline, energy coverage percentage, federal/state incentive estimate.\n2. **Roof Condition** — AI roof condition score (0-10), condition category, material identification, damage indicators, and risk assessment, from AI analysis of aerial imagery.\n\n## When to use it\n\n- Pre-screen properties for solar installation viability.\n- Underwrite roof replacement cost for an investor offer.\n- Add a solar-readiness flag to a property report.\n\n## Performance\n\n**This is an expensive, slow endpoint — use a 90-second client timeout and cache responses.**\n\n## Response shape\n\nThe response shape varies with the optional query parameters:\n\n- `detailed=true` — adds the raw `solar_potential.data` blob and includes both `roof_image_url` and `roof_image_base64` in `roof_condition.imagery`.\n- `agent=false` — sets `roof_condition.analysis` to `null` (skips the AI roof analysis).\n\nIf the roof image fails to upload to storage, `roof_condition.imagery` contains `roof_image_base64` (raw base64 PNG) instead of `roof_image_url`. Individual entries in `solar_layers` may be missing if a particular data layer was unavailable for the address.\n\n## FAQ\n\n### Why is `agent=true` the default?\nWithout it, the roof condition section is skipped (you get solar potential only). The AI roof analysis is the expensive part but it's what makes the endpoint useful — leave it on unless you specifically need solar-only.\n\n### What if the building isn't covered?\nReturns a clear error indicating imagery unavailable. Charges 0 credits in that case.",
        "summary": "Solar potential + AI roof condition for a property",
        "parameters": [
          {
            "in": "query",
            "name": "address",
            "schema": {
              "type": "string"
            },
            "description": "Full property address.",
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          },
          {
            "in": "query",
            "name": "agent",
            "schema": {
              "type": "boolean"
            },
            "description": "Run the AI roof analysis. Default `true`. Set `false` to skip it (sets `roof_condition.analysis` to null)."
          },
          {
            "in": "query",
            "name": "detailed",
            "schema": {
              "type": "boolean"
            },
            "description": "Include the raw solar data blob + base64 roof image alongside the storage URL. Default `false`."
          }
        ],
        "tags": ["AI-Powered Analysis"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "address": "4411 E Hidden Oak St, Springfield, MO, 65802",
                      "imagery_quality": {
                        "quality": "HIGH",
                        "description": "Solar data is derived from aerial imagery captured at low-altitude"
                      },
                      "imagery_date": "2022-06-17",
                      "solar_potential": {
                        "max_sunshine_hours_per_year": 1690.1926,
                        "summary": {
                          "panels_count": 77,
                          "installation_size_kw": 30.8,
                          "yearly_energy_kwh": 41792.2,
                          "energy_covered_percent": 99.4,
                          "installation_cost_usd": 56122,
                          "federal_incentive_usd": 24052,
                          "cost_without_solar_usd": 105549,
                          "cost_with_solar_usd": 52441,
                          "savings_usd": 53108,
                          "break_even_year": 9,
                          "cost_analysis": [
                            {
                              "year": 1,
                              "cost_with_solar_usd": 49.14,
                              "cost_without_solar_usd": 4200,
                              "cumulative_with_solar_usd": 32119.14,
                              "cumulative_without_solar_usd": 4200
                            },
                            {
                              "year": 2,
                              "cost_with_solar_usd": 68.69,
                              "cost_without_solar_usd": 4127.31,
                              "cumulative_with_solar_usd": 32187.83,
                              "cumulative_without_solar_usd": 8327.31
                            }
                          ],
                          "defaults_used": {
                            "dc_to_ac_derate": 0.85,
                            "efficiency_depreciation_factor": 0.995,
                            "cost_increase_factor": 1.022,
                            "discount_rate": 1.04,
                            "installation_lifespan_years": 20,
                            "monthly_bill_usd": 350,
                            "energy_cost_per_kwh_usd": 0.0993,
                            "installation_cost_per_watt_usd": 1.82,
                            "panel_capacity_watts": 400
                          }
                        }
                      },
                      "roof_condition": {
                        "agent": true,
                        "imagery": {
                          "roof_image_url": "https://renovation-portal-bucket.s3.amazonaws.com/solar/roof-images/a272edda41594b4d89a4be434dc0ac10.png?AWSAccessKeyId=AKIASRSZYAQKL5HFFSF4&Signature=Jsn2mnNBYVFC8kkJb3Bxputl%2FJs%3D&Expires=1781039747"
                        },
                        "analysis": {
                          "condition_score": 9,
                          "condition_category": "Good",
                          "visible_damage_indicators": [],
                          "material_identified": "Asphalt Shingles",
                          "structural_integrity_flag": false,
                          "structural_integrity_notes": "",
                          "uv_damage_risk": "High",
                          "uv_damage_risk_summary": "The roof receives significant direct sunlight, especially on its primary slopes which are exposed to the sun throughout the day. This high exposure to solar radiation increases the risk of UV degradation over time.",
                          "moisture_rot_risk": "Medium",
                          "moisture_rot_risk_summary": "While some sections of the roof receive less direct sunlight, which could potentially retain moisture longer, the overall sun exposure on the property generally promotes good drying conditions. Therefore, the risk of moisture-related issues is moderate."
                        }
                      },
                      "solar_layers": {
                        "annual_flux": {
                          "url": "https://renovation-portal-bucket.s3.amazonaws.com/solar/layer-images/706172f5a6654dfeb75f0e0a132b5552.png?AWSAccessKeyId=AKIASRSZYAQKL5HFFSF4&Signature=iCcRHpONo%2FgfTyKP63q5xdr%2Bh5c%3D&Expires=1781039750",
                          "type": "image/png"
                        },
                        "monthly_flux": {
                          "url": "https://renovation-portal-bucket.s3.amazonaws.com/solar/layer-images/2ba0316d11fd41e6b19a8884e7719b6e.gif?AWSAccessKeyId=AKIASRSZYAQKL5HFFSF4&Signature=vjoa4sjxfeQtohUGfu8kqz43fNw%3D&Expires=1781039750",
                          "type": "image/gif"
                        },
                        "hourly_shade": {
                          "url": "https://renovation-portal-bucket.s3.amazonaws.com/solar/layer-images/665000db09e245979240fc215a098b79.gif?AWSAccessKeyId=AKIASRSZYAQKL5HFFSF4&Signature=XIiExhhOXkrK%2BHqBJ1eLshb%2BsTM%3D&Expires=1781039750",
                          "type": "image/gif"
                        },
                        "dsm_height_map": {
                          "url": "https://renovation-portal-bucket.s3.amazonaws.com/solar/layer-images/5a1e7a31051749a29095b4a4e0b7100b.png?AWSAccessKeyId=AKIASRSZYAQKL5HFFSF4&Signature=kY%2FzudRIk6ZMmsIvCA%2B5obW7mRY%3D&Expires=1781039750",
                          "type": "image/png"
                        }
                      }
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Not found — the address or identifier did not resolve to a record. Costs 0 credits."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Upstream data provider is temporarily unavailable — retry with backoff."
          }
        },
        "x-slug": "solar-analysis",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/solar/analysis/?address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/solar/analysis/', params={'address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 4
      }
    },
    "/api/mortgage-lien/analysis/": {
      "get": {
        "operationId": "get_mortgage_lien_analysis",
        "description": "## What it returns\n\nMortgage and lien records for a US property — current and historical mortgages, lien summary, involuntary liens, pre-foreclosure status, and data quality metadata. Sourced from a county-records aggregator and cached for 7 days; cached responses cost 0 credits.\n\n## Performance\n\n**Fresh lookups are slow — use a 60-second client timeout and cache responses (we cache for 7 days; cached reads are fast and free).**\n\n## When to use it\n\n- Identify distressed properties (high lien-to-value ratio, pre-foreclosure).\n- Pre-screen wholesale outreach lists for owner-equity position.\n- Disclose lien position to a buyer or lender.\n\n## Pricing\n\n5 credits per **fresh** request. Cached responses (within 7 days of the prior fetch for the same address) cost 0 credits.\n\n## FAQ\n\n### Is this real-time?\nNo — mortgage recordings post to county records with days-to-weeks lag. The 7-day cache reflects that natural cadence.\n\n### What if the property has no mortgage?\nReturns an empty mortgages array and the lien summary reflects equity-only status. Still counts as 5 credits (the call ran).",
        "summary": "Mortgage and lien data for a US property",
        "parameters": [
          {
            "in": "query",
            "name": "address",
            "schema": {
              "type": "string"
            },
            "description": "Full property address.",
            "required": true,
            "example": "4411 E Hidden Oak St, Springfield, MO, 65802"
          }
        ],
        "tags": ["Market Data"],
        "security": [
          {
            "CookieJWT": []
          },
          {
            "tokenAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                },
                "examples": {
                  "Example response": {
                    "summary": "Example response",
                    "value": {
                      "property_address": "4411 E Hidden Oak St",
                      "lookup_timestamp": "2026-06-08T21:16:01Z",
                      "current_mortgages": [],
                      "historical_mortgages": [
                        {
                          "lien_type": "voluntary",
                          "mortgage_type": "Building or Construction Loan",
                          "lender_name": "SULLIVAN BANK",
                          "lender_nmls_id": null,
                          "original_loan_amount": 460000,
                          "estimated_outstanding_balance": null,
                          "interest_rate": 6.71,
                          "rate_type": null,
                          "loan_term_months": 360,
                          "origination_date": "2023-07-26",
                          "maturity_date": null,
                          "recording_date": "2023-07-26",
                          "grantor": "CRM BUILT LLC",
                          "grantee": "SULLIVAN BANK",
                          "document_number": null
                        }
                      ],
                      "lien_summary": {
                        "total_open_lien_count": 0,
                        "total_open_lien_amount": 0,
                        "estimated_equity": null,
                        "estimated_ltv": null
                      },
                      "involuntary_liens": [],
                      "pre_foreclosure": {
                        "is_in_pre_foreclosure": false,
                        "nod_date": null,
                        "auction_date": null,
                        "default_amount": null
                      },
                      "data_quality": {
                        "confidence": null,
                        "last_updated": "2026-06-08",
                        "coverage_notes": null
                      }
                    }
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad request — a required parameter is missing or failed validation. Costs 0 credits."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Authentication failed — missing or invalid API key. Costs 0 credits."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Payment required — no active subscription or insufficient credit balance. Costs 0 credits."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Not found — the address or identifier did not resolve to a record. Costs 0 credits."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            },
            "description": "Bad gateway — the upstream county-records aggregator failed or timed out on a fresh lookup. Fresh lookups are slow, so use a 60-second client timeout and retry with backoff; a successful retry is cached (and free) for 7 days."
          }
        },
        "x-slug": "mortgage-lien-analysis",
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl 'https://developers.homesage.ai/api/mortgage-lien/analysis/?address=4411%20E%20Hidden%20Oak%20St%20Springfield%20MO%2065802' -H 'Authorization: Token YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\nr = requests.get('https://developers.homesage.ai/api/mortgage-lien/analysis/', params={'address': '4411 E Hidden Oak St Springfield MO 65802'}, headers={'Authorization': 'Token YOUR_API_KEY'})"
          }
        ],
        "x-playground": "enabled",
        "x-drift-target": "cassette",
        "x-credits": 5
      }
    }
  },
  "components": {
    "schemas": {
      "AddressLookupError": {
        "type": "object",
        "description": "Returned with HTTP 404 (and 0 credits) when a property_address cannot be confidently matched to a single property. did_you_mean lists actionable candidate addresses to retry with — surface them to the user rather than treating the 404 as a dead end. An empty array means no close match was found.",
        "properties": {
          "error": {
            "type": "string",
            "example": "We couldn't find an exact match for the address you provided."
          },
          "requested_address": {
            "type": "string",
            "description": "The address string the client sent.",
            "example": "4411"
          },
          "did_you_mean": {
            "type": "array",
            "description": "Candidate addresses to suggest to the user; empty when there is no close match.",
            "items": {
              "type": "object",
              "properties": {
                "address": {
                  "type": "string",
                  "example": "4411 E Cedar Rd, Williams, AZ, 86046"
                },
                "mpr_id": {
                  "type": "string",
                  "description": "HomeSage property id for the suggested address; reusable in follow-up calls.",
                  "example": "2393816597"
                }
              }
            }
          }
        }
      },
      "AutoCompleteResponse": {
        "type": "object",
        "properties": {
          "outcome": {
            "type": "string",
            "description": "Always `success` on 200."
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutoCompleteSuggestion"
            },
            "description": "0–5 address suggestions ranked by relevance."
          },
          "search_input": {
            "type": "string",
            "description": "The `input` query the user provided. Echoed back for client-side cache key construction."
          },
          "results_count": {
            "type": "integer",
            "description": "`len(data)` for convenience."
          }
        },
        "required": ["data", "outcome", "results_count", "search_input"]
      },
      "AutoCompleteSuggestion": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Display string for the suggestion (full address)."
          },
          "address": {
            "type": "string",
            "description": "Same as `text` — full address with `, USA` suffix."
          },
          "city": {
            "type": "string"
          },
          "postal_code": {
            "type": "string"
          },
          "state_code": {
            "type": "string",
            "description": "2-letter US state code."
          }
        },
        "required": ["address", "city", "postal_code", "state_code", "text"]
      },
      "BulkPropertyInfoResponse": {
        "type": "object",
        "properties": {
          "total_count": {
            "type": "integer",
            "description": "Total matches in the source, before pagination."
          },
          "page": {
            "type": "integer",
            "description": "1-based."
          },
          "page_size": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          },
          "properties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkPropertyItem"
            }
          }
        },
        "required": ["page", "page_size", "properties", "total_count", "total_pages"]
      },
      "BulkPropertyItem": {
        "type": "object",
        "description": "One row in the `properties` array of `GET /api/properties/bulk-info/`.\n\nDiffers from `PropertyInfoResponseSerializer` — bulk returns flatter ROI-\nfocused fields rather than the deeply nested per-property breakdown.",
        "properties": {
          "address": {
            "type": "string",
            "nullable": true
          },
          "list_price": {
            "type": "integer",
            "nullable": true
          },
          "avm": {
            "type": "integer",
            "nullable": true
          },
          "avm_low": {
            "type": "integer",
            "nullable": true
          },
          "avm_high": {
            "type": "integer",
            "nullable": true
          },
          "avm_confidence": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "avm_disagreement": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "total_financing_cost": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "total_holding_cost": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "total_loan_amount": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "total_project_cost": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "holding_cost": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "interest": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "points": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "contingency": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "cost_at_purchase": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "cost_at_sale": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "downpayment": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "potential_roi": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "weighted_pfs": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "primary_photo": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "`{href, description}` — first photo for hover thumbnails."
          },
          "dom": {
            "type": "integer",
            "nullable": true
          },
          "neighborhood": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "address",
          "avm",
          "avm_confidence",
          "avm_disagreement",
          "avm_high",
          "avm_low",
          "contingency",
          "cost_at_purchase",
          "cost_at_sale",
          "dom",
          "downpayment",
          "holding_cost",
          "interest",
          "list_price",
          "neighborhood",
          "points",
          "potential_roi",
          "primary_photo",
          "total_financing_cost",
          "total_holding_cost",
          "total_loan_amount",
          "total_project_cost",
          "weighted_pfs"
        ]
      },
      "CreditBalanceResponse": {
        "type": "object",
        "description": "The shape returned by `GET /api/usage/credits/`.",
        "properties": {
          "credits_remaining": {
            "type": "integer",
            "nullable": true,
            "description": "Credits left in the current billing period. `null` for unlimited or custom plans with no fixed unit cap."
          },
          "credits_used": {
            "type": "integer",
            "description": "Credits consumed since the period started."
          },
          "total_credits": {
            "type": "integer",
            "nullable": true,
            "description": "The plan's per-period credit allowance. `null` for unlimited or custom plans."
          },
          "usage_percentage": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "`credits_used / total_credits * 100`, rounded to 2 decimals. `null` when `total_credits` is unknown or zero."
          },
          "plan_name": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable plan name (e.g. `Sandbox`, `Professional`)."
          },
          "subscription_status": {
            "type": "string",
            "description": "Stripe-derived status — `active`, `trialing`, `past_due`, `canceled`, etc. Empty string for accounts with no subscription."
          },
          "renewal_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the current credit allowance resets. For yearly plans, the next monthly credit-reset; for monthly plans, the next billing period boundary. ISO-8601."
          },
          "billing_period_start": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Start of the current billing period. ISO-8601."
          }
        },
        "required": [
          "billing_period_start",
          "credits_remaining",
          "credits_used",
          "plan_name",
          "renewal_date",
          "subscription_status",
          "total_credits",
          "usage_percentage"
        ]
      },
      "PropertyConditionCustomPhotosRequestRequest": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "minLength": 1,
            "description": "Property address. Either `address` or `image_urls` must be provided."
          },
          "image_urls": {
            "type": "string",
            "minLength": 1,
            "description": "Comma-separated image URLs (up to 25). The playground supports URL-based images; file uploads require a multipart request from your own code."
          }
        }
      },
      "PropertyInfoCoordinates": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "format": "double",
            "nullable": true
          }
        },
        "required": ["latitude", "longitude"]
      },
      "PropertyInfoResponse": {
        "type": "object",
        "description": "Shape returned by `GET /api/properties/info/` and `GET /api/properties/updated-info/`.\n\nDeeply nested sub-objects (`property_features`, `lot`, `interior_features`,\n`school_ratings`, etc.) are free-form objects whose exact shape can evolve\nbetween releases.",
        "properties": {
          "address": {
            "type": "string",
            "nullable": true
          },
          "coordinates": {
            "$ref": "#/components/schemas/PropertyInfoCoordinates"
          },
          "list_date": {
            "type": "string",
            "nullable": true,
            "description": "ISO-8601. `null` for off-market."
          },
          "status": {
            "type": "string",
            "nullable": true,
            "description": "`for_sale`, `sold`, `off_market`, etc."
          },
          "listing_price": {
            "type": "integer",
            "nullable": true,
            "description": "`null` unless `status == for_sale`."
          },
          "estimated_value": {
            "type": "integer",
            "nullable": true,
            "description": "AVM — `null` when not computed."
          },
          "sf": {
            "type": "integer",
            "nullable": true,
            "description": "Living area, square feet. May be `0` when source data lacks size."
          },
          "psf": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Price per square foot (`listing_price` or `estimated_value` ÷ `sf`)."
          },
          "dom": {
            "type": "integer",
            "nullable": true,
            "description": "Days on market. `null` when listing-history dates are missing."
          },
          "property_features": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Beds, baths, stories, type, etc."
          },
          "location_community": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "building_info": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "lot": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "parking": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "interior_features": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "home_value": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Tax-assessed value history when available."
          },
          "utilities": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "listing_office": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "listing_details": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "property_history": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": "Listing/sold/price-change events ordered most-recent-first."
          },
          "school_ratings": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": "Nearby schools with rating, distance, and grade-level."
          }
        },
        "required": [
          "address",
          "building_info",
          "coordinates",
          "dom",
          "estimated_value",
          "home_value",
          "interior_features",
          "list_date",
          "listing_details",
          "listing_office",
          "listing_price",
          "location_community",
          "lot",
          "parking",
          "property_features",
          "property_history",
          "psf",
          "school_ratings",
          "sf",
          "status",
          "utilities"
        ]
      },
      "SkipTraceAddress": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "nullable": true
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true,
            "description": "`current`, `previous`, `mailing`."
          },
          "first_seen": {
            "type": "string",
            "nullable": true,
            "description": "`YYYY-MM-DD` of first observation in source records."
          },
          "last_seen": {
            "type": "string",
            "nullable": true,
            "description": "`YYYY-MM-DD` of most recent observation."
          }
        },
        "required": ["address", "city", "first_seen", "last_seen", "state", "type", "zip"]
      },
      "SkipTraceEmail": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "is_verified": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` if SMTP-verified by the provider. `null` if not checked."
          }
        },
        "required": ["address", "is_verified"]
      },
      "SkipTracePersonDetailsRequestRequest": {
        "type": "object",
        "description": "Request body for `POST /api/properties/skip-tracing/person-details/`.",
        "properties": {
          "person_id": {
            "type": "string",
            "minLength": 1,
            "description": "Stable identifier returned by `skip-tracing/associated-people` for a specific person. Not a free-form name — must come from a prior skip-trace call."
          }
        },
        "required": ["person_id"]
      },
      "SkipTracePersonDetailsResponse": {
        "type": "object",
        "description": "Response body for `POST /api/properties/skip-tracing/person-details/`.\n\nTop-level arrays are returned as-is; individual record shapes inside the\narrays vary by source data quality and are not strictly validated.",
        "properties": {
          "person_details": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": "Person-level facts: name, age, DOB, education, employment. One or more entries when the provider has overlapping records."
          },
          "current_addresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkipTraceAddress"
            },
            "description": "Current address(es). May be empty."
          },
          "phone_numbers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkipTracePhone"
            },
            "description": "All phone numbers attributed to this person."
          },
          "email_addresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkipTraceEmail"
            },
            "description": "All emails attributed to this person."
          },
          "previous_addresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkipTraceAddress"
            },
            "description": "Historical addresses, when available."
          },
          "relatives": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": "`{name, relationship, person_id}` objects."
          },
          "associates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": "Non-family related persons."
          }
        },
        "required": ["current_addresses", "email_addresses", "person_details", "phone_numbers"]
      },
      "SkipTracePhone": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "nullable": true,
            "description": "E.164 format when normalizable, else raw."
          },
          "type": {
            "type": "string",
            "nullable": true,
            "description": "`mobile`, `landline`, `voip`, `unknown`."
          },
          "is_connected": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` if the provider's last connectivity check succeeded. `null` if not checked."
          }
        },
        "required": ["is_connected", "number", "type"]
      },
      "SoldPropertyItem": {
        "type": "object",
        "description": "One sold-property record in the response array of `GET /api/properties/sold/by-zip/`.",
        "properties": {
          "property_address": {
            "type": "string",
            "nullable": true,
            "description": "Full street address. May be `null` when address components are missing in the source record."
          },
          "longitude": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "WGS-84 longitude."
          },
          "latitude": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "WGS-84 latitude."
          },
          "sold_date": {
            "type": "string",
            "nullable": true,
            "description": "Sale date in `YYYY-MM-DD`. Always within the last 365 days (older sales are filtered out)."
          },
          "sold_price": {
            "type": "integer",
            "nullable": true,
            "description": "Sale price in USD. `null` when the source suppresses price (off-market, private sale, MLS gag)."
          },
          "total_size": {
            "type": "integer",
            "nullable": true,
            "description": "Living area in square feet."
          },
          "bedrooms": {
            "type": "integer",
            "nullable": true
          },
          "bathrooms": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Bathroom count (may be fractional — `2.5` for 2 full + 1 half)."
          },
          "year_built": {
            "type": "integer",
            "nullable": true
          },
          "property_type": {
            "type": "string",
            "nullable": true,
            "description": "`single_family`, `condo`, `townhouse`, `multi_family`, etc."
          },
          "stories": {
            "type": "integer",
            "nullable": true
          },
          "parking": {
            "type": "integer",
            "nullable": true,
            "description": "Parking spaces (covered + uncovered)."
          },
          "lot_size": {
            "type": "integer",
            "nullable": true,
            "description": "Lot size in square feet."
          },
          "dom": {
            "type": "integer",
            "nullable": true,
            "description": "Days on market before the sale. Computed best-effort; `null` when listing-history dates are unavailable."
          }
        },
        "required": [
          "bathrooms",
          "bedrooms",
          "dom",
          "latitude",
          "longitude",
          "lot_size",
          "parking",
          "property_address",
          "property_type",
          "sold_date",
          "sold_price",
          "stories",
          "total_size",
          "year_built"
        ]
      }
    },
    "securitySchemes": {
      "CookieJWT": {
        "type": "apiKey",
        "in": "cookie",
        "name": "hs_access",
        "description": "HttpOnly JWT cookie set by the BFF login flow. SPA clients send it automatically with `credentials: \"include\"`."
      },
      "tokenAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "API key authentication. The key is a JWT minted at `/api/keys/generate/` (manage keys in the developer portal). Send it as `Authorization: Bearer <token>`."
      }
    }
  },
  "servers": [
    {
      "url": "https://developers.homesage.ai",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Property Search",
      "description": "Search the property database by investment criteria — free count preview, then a charged result set (1 credit per property)."
    },
    {
      "name": "Property Lookup",
      "description": "Address autocomplete, property info, bulk lookup."
    },
    {
      "name": "Property Valuation",
      "description": "Current value, investment potential, rental and renovation returns."
    },
    {
      "name": "AI-Powered Analysis",
      "description": "Comps, property condition, solar, full report — vision/LLM-derived insights."
    },
    {
      "name": "Skip Tracing",
      "description": "Owner lookup and associated-people enrichment from public records and skip-trace providers."
    },
    {
      "name": "Market Data",
      "description": "Sold-by-zip aggregates and mortgage/lien analysis."
    },
    {
      "name": "Risk & Diligence",
      "description": "Location-level red flags (flood, crime, environmental, school-district)."
    },
    {
      "name": "Account",
      "description": "Credit balance and account utility endpoints."
    }
  ]
}
