{
  "openapi": "3.1.0",
  "info": {
    "title": "PropRaven API",
    "version": "1.0.1",
    "description": "National property intelligence API providing access to 180M+ US parcels with ownership, valuation, permit, deed, risk, and market data.",
    "contact": {
      "name": "PropRaven Support",
      "url": "https://propraven.com/docs",
      "email": "support@propraven.com"
    },
    "license": {
      "name": "Commercial",
      "url": "https://propraven.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.propraven.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/parcels/{id}": {
      "get": {
        "operationId": "getParcel",
        "summary": "Get parcel by ID",
        "description": "Retrieve a single parcel by its composite ID (county_fips:parcel_id).",
        "tags": [
          "Parcels"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Composite parcel identifier in the format county_fips:parcel_id (e.g., 37183:0012345).",
            "schema": {
              "type": "string",
              "example": "37183:0012345"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Parcel found.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Parcel"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/{id}/owner": {
      "get": {
        "operationId": "getParcelOwner",
        "summary": "Get parcel owner details and portfolio",
        "description": "Retrieve the owner of a parcel along with their portfolio summary and list of properties.",
        "tags": [
          "Parcels"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Composite parcel identifier (county_fips:parcel_id).",
            "schema": {
              "type": "string",
              "example": "37183:0012345"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owner details returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "owner_name": {
                      "type": "string",
                      "example": "SMITH JOHN A"
                    },
                    "entity_type": {
                      "type": "string",
                      "enum": [
                        "individual",
                        "corporation",
                        "llc",
                        "trust",
                        "government",
                        "other"
                      ],
                      "example": "individual"
                    },
                    "mailing_address": {
                      "type": "string",
                      "example": "123 Main St, Raleigh, NC 27601"
                    },
                    "portfolio_summary": {
                      "type": "object",
                      "properties": {
                        "property_count": {
                          "type": "integer",
                          "example": 5
                        },
                        "total_assessed_value": {
                          "type": "number",
                          "example": 1250000
                        },
                        "states": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "example": [
                            "NC",
                            "SC"
                          ]
                        }
                      }
                    },
                    "properties": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/{id}/permits": {
      "get": {
        "operationId": "getParcelPermits",
        "summary": "Get parcel permits",
        "description": "Retrieve building and construction permits associated with a parcel.",
        "tags": [
          "Parcels"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Composite parcel identifier (county_fips:parcel_id).",
            "schema": {
              "type": "string",
              "example": "37183:0012345"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Permits returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Permit"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/{id}/deeds": {
      "get": {
        "operationId": "getParcelDeeds",
        "summary": "Get parcel deed history",
        "description": "Retrieve deed transactions and transfer history for a parcel.",
        "tags": [
          "Parcels"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Composite parcel identifier (county_fips:parcel_id).",
            "schema": {
              "type": "string",
              "example": "37183:0012345"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deeds returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Deed"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/{id}/risks": {
      "get": {
        "operationId": "getParcelRisks",
        "summary": "Get parcel risk assessment",
        "description": "Retrieve flood, wildfire, air quality, and crime risk data for a parcel.",
        "tags": [
          "Parcels"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Composite parcel identifier (county_fips:parcel_id).",
            "schema": {
              "type": "string",
              "example": "37183:0012345"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Risk assessment returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RiskAssessment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/search": {
      "post": {
        "operationId": "searchParcels",
        "summary": "Search parcels",
        "description": "Search parcels within geographic bounds with optional filters, sorting, and pagination.",
        "tags": [
          "Search"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "bounds"
                ],
                "properties": {
                  "bounds": {
                    "type": "object",
                    "required": [
                      "north",
                      "south",
                      "east",
                      "west"
                    ],
                    "properties": {
                      "north": {
                        "type": "number",
                        "format": "double",
                        "example": 35.85
                      },
                      "south": {
                        "type": "number",
                        "format": "double",
                        "example": 35.75
                      },
                      "east": {
                        "type": "number",
                        "format": "double",
                        "example": -78.55
                      },
                      "west": {
                        "type": "number",
                        "format": "double",
                        "example": -78.7
                      }
                    }
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "zoningCategories": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Filter by zoning category (e.g., residential, commercial, industrial).",
                        "example": [
                          "residential",
                          "commercial"
                        ]
                      },
                      "ownerTypes": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "individual",
                            "corporation",
                            "llc",
                            "trust",
                            "government",
                            "other"
                          ]
                        },
                        "description": "Filter by owner entity type."
                      },
                      "absenteeOnly": {
                        "type": "boolean",
                        "description": "Only return parcels with absentee owners.",
                        "default": false
                      },
                      "valueRange": {
                        "type": "object",
                        "properties": {
                          "min": {
                            "type": "number",
                            "example": 100000
                          },
                          "max": {
                            "type": "number",
                            "example": 500000
                          }
                        },
                        "description": "Filter by assessed value range."
                      },
                      "yearBuiltRange": {
                        "type": "object",
                        "properties": {
                          "min": {
                            "type": "integer",
                            "example": 1990
                          },
                          "max": {
                            "type": "integer",
                            "example": 2024
                          }
                        },
                        "description": "Filter by year built range."
                      },
                      "acreageRange": {
                        "type": "object",
                        "properties": {
                          "min": {
                            "type": "number",
                            "example": 0.5
                          },
                          "max": {
                            "type": "number",
                            "example": 10
                          }
                        },
                        "description": "Filter by acreage range."
                      }
                    }
                  },
                  "sort": {
                    "type": "string",
                    "enum": [
                      "assessed_value",
                      "sale_price",
                      "acreage",
                      "year_built",
                      "deal_score"
                    ],
                    "description": "Sort field.",
                    "example": "assessed_value"
                  },
                  "order": {
                    "type": "string",
                    "enum": [
                      "asc",
                      "desc"
                    ],
                    "default": "desc"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 500,
                    "default": 100,
                    "description": "Number of results to return."
                  },
                  "offset": {
                    "type": "integer",
                    "minimum": 0,
                    "default": 0,
                    "description": "Number of results to skip for pagination."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Search results returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    },
                    "total": {
                      "type": "integer",
                      "example": 1432
                    },
                    "limit": {
                      "type": "integer",
                      "example": 100
                    },
                    "offset": {
                      "type": "integer",
                      "example": 0
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/coverage": {
      "get": {
        "operationId": "getCoverage",
        "summary": "Get coverage statistics",
        "description": "Retrieve parcel coverage statistics at the state or county level.",
        "tags": [
          "Coverage"
        ],
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "State FIPS code or abbreviation to filter coverage to a specific state and return county-level breakdown.",
            "schema": {
              "type": "string",
              "example": "37"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Coverage data returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_parcels": {
                      "type": "integer",
                      "example": 180000000
                    },
                    "states_covered": {
                      "type": "integer",
                      "example": 50
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "state_fips": {
                            "type": "string",
                            "example": "37"
                          },
                          "state_name": {
                            "type": "string",
                            "example": "North Carolina"
                          },
                          "county_fips": {
                            "type": "string",
                            "nullable": true,
                            "example": "37183"
                          },
                          "county_name": {
                            "type": "string",
                            "nullable": true,
                            "example": "Wake"
                          },
                          "parcel_count": {
                            "type": "integer",
                            "example": 450000
                          },
                          "geocoded_pct": {
                            "type": "number",
                            "format": "float",
                            "example": 92.5
                          },
                          "owner_pct": {
                            "type": "number",
                            "format": "float",
                            "example": 88.3
                          },
                          "value_pct": {
                            "type": "number",
                            "format": "float",
                            "example": 85.1
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/absentee": {
      "get": {
        "operationId": "getAbsenteeOwners",
        "summary": "Find absentee owners",
        "description": "Retrieve parcels owned by absentee owners, useful for off-market deal sourcing.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37183"
            },
            "description": "Filter by county FIPS code."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37"
            },
            "description": "Filter by state FIPS code."
          },
          {
            "name": "min_value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "example": 50000
            },
            "description": "Minimum assessed value."
          },
          {
            "name": "out_of_state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Only return owners whose mailing address is in a different state."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Absentee owner parcels returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/flips": {
      "get": {
        "operationId": "getFlips",
        "summary": "Find property flips",
        "description": "Retrieve recently flipped properties. Use ?view=flippers to get a ranked list of top flippers instead.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37183"
            },
            "description": "Filter by county FIPS code."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37"
            },
            "description": "Filter by state FIPS code."
          },
          {
            "name": "flip_tier",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "quick",
                "standard",
                "long"
              ],
              "example": "quick"
            },
            "description": "Filter by flip speed tier (quick: <6mo, standard: 6-12mo, long: 12-24mo)."
          },
          {
            "name": "min_profit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "example": 25000
            },
            "description": "Minimum estimated profit."
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "flippers"
              ]
            },
            "description": "Set to 'flippers' to return a ranked list of top flippers instead of individual flips."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Flips or flippers returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "county_fips": {
                            "type": "string",
                            "example": "37183"
                          },
                          "parcel_id": {
                            "type": "string"
                          },
                          "address": {
                            "type": "string"
                          },
                          "buy_date": {
                            "type": "string",
                            "format": "date"
                          },
                          "buy_price": {
                            "type": "number"
                          },
                          "sell_date": {
                            "type": "string",
                            "format": "date"
                          },
                          "sell_price": {
                            "type": "number"
                          },
                          "profit": {
                            "type": "number"
                          },
                          "hold_days": {
                            "type": "integer"
                          },
                          "flip_tier": {
                            "type": "string",
                            "enum": [
                              "quick",
                              "standard",
                              "long"
                            ]
                          },
                          "buyer_name": {
                            "type": "string"
                          },
                          "seller_name": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/market/counties": {
      "get": {
        "operationId": "getCountyMarketStats",
        "summary": "Get county market statistics",
        "description": "Retrieve real estate market statistics aggregated at the county level, including sale counts, median prices, and year-over-year changes.",
        "tags": [
          "Market"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37"
            },
            "description": "Filter by state FIPS code."
          },
          {
            "name": "min_sales",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "example": 50
            },
            "description": "Minimum number of sales in the period to include a county."
          },
          {
            "name": "quarter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2025Q4"
            },
            "description": "Specific quarter to retrieve (e.g., 2025Q4). Defaults to latest available."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "sale_count",
                "median_price",
                "yoy_change",
                "county_name"
              ],
              "default": "sale_count"
            },
            "description": "Sort field."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "County market stats returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "county_fips": {
                            "type": "string",
                            "example": "37183"
                          },
                          "county_name": {
                            "type": "string",
                            "example": "Wake"
                          },
                          "state_fips": {
                            "type": "string",
                            "example": "37"
                          },
                          "state_abbr": {
                            "type": "string",
                            "example": "NC"
                          },
                          "quarter": {
                            "type": "string",
                            "example": "2025Q4"
                          },
                          "sale_count": {
                            "type": "integer",
                            "example": 3200
                          },
                          "median_price": {
                            "type": "number",
                            "example": 385000
                          },
                          "avg_price": {
                            "type": "number",
                            "example": 425000
                          },
                          "yoy_change": {
                            "type": "number",
                            "format": "float",
                            "description": "Year-over-year median price change as a decimal (e.g., 0.05 = 5%).",
                            "example": 0.05
                          },
                          "avg_days_on_market": {
                            "type": "integer",
                            "example": 28
                          }
                        }
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/market/trends": {
      "get": {
        "operationId": "getMarketTrends",
        "summary": "Get market trends",
        "description": "Retrieve quarterly time series of market metrics for one or more counties or a state.",
        "tags": [
          "Market"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37183,37063"
            },
            "description": "Comma-separated list of county FIPS codes."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37"
            },
            "description": "State FIPS code. Used if county_fips is not provided."
          }
        ],
        "responses": {
          "200": {
            "description": "Market trend time series returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "county_fips": {
                            "type": "string",
                            "example": "37183"
                          },
                          "county_name": {
                            "type": "string",
                            "example": "Wake"
                          },
                          "quarters": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "quarter": {
                                  "type": "string",
                                  "example": "2025Q4"
                                },
                                "sale_count": {
                                  "type": "integer",
                                  "example": 3200
                                },
                                "median_price": {
                                  "type": "number",
                                  "example": 385000
                                },
                                "avg_price": {
                                  "type": "number",
                                  "example": 425000
                                },
                                "yoy_change": {
                                  "type": "number",
                                  "format": "float",
                                  "example": 0.05
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/owners/search": {
      "get": {
        "operationId": "searchOwners",
        "summary": "Search property owners",
        "description": "Search for property owners by name. Returns owner profiles with property counts and portfolio values.",
        "tags": [
          "Owners"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "BLACKROCK"
            },
            "description": "Search query for owner name."
          },
          {
            "name": "min_properties",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "example": 5
            },
            "description": "Minimum number of properties owned."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owner search results returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Owner"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/owners/{name}": {
      "get": {
        "operationId": "getOwnerProfile",
        "summary": "Get owner profile",
        "description": "Retrieve a specific owner profile by name, including property count, total assessed value, entity type, and states.",
        "tags": [
          "Owners"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "BLACKROCK FUND ADVISORS"
            },
            "description": "Owner name (URL-encoded)."
          }
        ],
        "responses": {
          "200": {
            "description": "Owner profile returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Owner"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/owners/{name}/properties": {
      "get": {
        "operationId": "getOwnerProperties",
        "summary": "Get owner's properties",
        "description": "Retrieve the list of properties owned by a specific owner.",
        "tags": [
          "Owners"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "BLACKROCK FUND ADVISORS"
            },
            "description": "Owner name (URL-encoded)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owner properties returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/owners/{name}/portfolio": {
      "get": {
        "operationId": "getOwnerPortfolio",
        "summary": "Get owner portfolio summary",
        "description": "Retrieve an owner's portfolio with aggregated summary statistics and property breakdown.",
        "tags": [
          "Owners"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "BLACKROCK FUND ADVISORS"
            },
            "description": "Owner name (URL-encoded)."
          }
        ],
        "responses": {
          "200": {
            "description": "Owner portfolio returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "owner_name": {
                      "type": "string",
                      "example": "BLACKROCK FUND ADVISORS"
                    },
                    "entity_type": {
                      "type": "string",
                      "enum": [
                        "individual",
                        "corporation",
                        "llc",
                        "trust",
                        "government",
                        "other"
                      ]
                    },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "property_count": {
                          "type": "integer",
                          "example": 142
                        },
                        "total_assessed_value": {
                          "type": "number",
                          "example": 85000000
                        },
                        "avg_assessed_value": {
                          "type": "number",
                          "example": 598591
                        },
                        "states": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "example": [
                            "NC",
                            "SC",
                            "GA",
                            "FL"
                          ]
                        },
                        "counties": {
                          "type": "integer",
                          "example": 23
                        },
                        "zoning_breakdown": {
                          "type": "object",
                          "additionalProperties": {
                            "type": "integer"
                          },
                          "example": {
                            "residential": 80,
                            "commercial": 45,
                            "industrial": 17
                          }
                        }
                      }
                    },
                    "properties": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/contractors": {
      "get": {
        "operationId": "searchContractors",
        "summary": "Search contractors by permit activity",
        "description": "Returns contractor profiles aggregated from 45M+ building permits. Each profile includes permit count, jurisdictions worked, total declared permit value, and activity dates. Use to identify active contractors in a market or find a specific contractor by name.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "SMITH CONSTRUCTION"
            },
            "description": "Contractor name search (case-insensitive substring)."
          },
          {
            "name": "min_permits",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 3,
              "minimum": 1
            },
            "description": "Minimum permit count to include."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "NC"
            },
            "description": "2-letter state filter."
          },
          {
            "name": "min_value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Minimum total declared permit value, USD."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Contractor profiles returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contractor"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/entities": {
      "get": {
        "operationId": "searchEntityOwnedParcels",
        "summary": "Find entity-owned parcels (LLC, Corp, Trust, LP)",
        "description": "Returns parcels owned by legal entities identified from owner-name pattern matching across 221M+ parcels. Pass `top=true` to get aggregated entity rankings instead of per-parcel rows. One of `county_fips`, `state_fips`, `search`, or `top` is required.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37183"
            },
            "description": "5-digit county FIPS filter."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37"
            },
            "description": "2-digit state FIPS filter."
          },
          {
            "name": "entity_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "LLC",
                "CORP",
                "TRUST",
                "LP",
                "LTD",
                "ASSOCIATION",
                "OTHER_ENTITY"
              ]
            },
            "description": "Filter by entity classification."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "BLACKSTONE"
            },
            "description": "Owner-name substring search."
          },
          {
            "name": "min_value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Minimum assessed value, USD."
          },
          {
            "name": "zoning",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Zoning substring filter."
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "If true, returns aggregated entity rankings with summary stats instead of per-parcel rows."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Entity-owned parcels or top-entity aggregates returned. Shape varies with the `top` parameter.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/EntityOwnedParcel"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/EntityAggregate"
                          }
                        },
                        "summary": {
                          "$ref": "#/components/schemas/EntitySummary"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "One of county_fips, state_fips, search, or top is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/high-land-ratio": {
      "get": {
        "operationId": "getHighLandRatioParcels",
        "summary": "Find parcels with high land-to-improvement ratio",
        "description": "Returns parcels where land value significantly exceeds improvement value \u2014 a signal for redevelopment, teardown, or assemblage opportunities. `county_fips` or `state_fips` is required.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "5-digit county FIPS filter."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "2-digit state FIPS filter."
          },
          {
            "name": "min_ratio",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "default": 3.0,
              "minimum": 1.0
            },
            "description": "Minimum land/improvement ratio."
          },
          {
            "name": "min_value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Minimum land assessed value, USD."
          },
          {
            "name": "zoning",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Zoning substring filter."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "High land-to-improvement-ratio parcels returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/HighLandRatioParcel"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Either county_fips or state_fips is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/lenders": {
      "get": {
        "operationId": "searchLenders",
        "summary": "Search lender profiles",
        "description": "Returns lender profiles aggregated from deed/mortgage transactions. Includes mortgage count, total volume, geographic spread, and a national rank.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "WELLS FARGO"
            },
            "description": "Lender name substring search."
          },
          {
            "name": "min_mortgages",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 2
            },
            "description": "Minimum mortgage count."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "NC"
            },
            "description": "2-letter state filter."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Lender profiles returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Lender"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/long-hold": {
      "get": {
        "operationId": "getLongHoldParcels",
        "summary": "Find long-held parcels (10+ years)",
        "description": "Returns parcels not sold in `min_years` or more. Long-hold owners are often motivated sellers \u2014 estate planning, deferred maintenance, life changes. `county_fips` or `state_fips` is required.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "5-digit county FIPS filter."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "2-digit state FIPS filter."
          },
          {
            "name": "min_years",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Minimum years held."
          },
          {
            "name": "hold_tier",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "10-15yr",
                "15-20yr",
                "20-30yr",
                "30yr+"
              ]
            },
            "description": "Filter by hold-period tier."
          },
          {
            "name": "min_value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Minimum assessed value, USD."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Long-hold parcels returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LongHoldParcel"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Either county_fips or state_fips is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/market": {
      "get": {
        "operationId": "getDealMarketSummary",
        "summary": "County-quarter transaction summary or affordability index",
        "description": "Default: returns county/quarter transaction summaries. Pass `view=affordability` to retrieve the home-affordability index instead (price-to-income ratios + rating).",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "view",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "affordability"
              ]
            },
            "description": "Switch to the affordability-index dataset."
          },
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "5-digit county FIPS filter."
          },
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "2-digit state FIPS filter."
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2024"
            },
            "description": "Year filter."
          },
          {
            "name": "rating",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "AFFORDABLE",
                "MODERATE",
                "EXPENSIVE",
                "VERY_EXPENSIVE"
              ]
            },
            "description": "Affordability-rating filter (only meaningful with view=affordability)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Market summary or affordability rows returned. Shape varies with the `view` parameter.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/MarketSummary"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AffordabilityRow"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/deals/portfolio-owners": {
      "get": {
        "operationId": "getPortfolioOwners",
        "summary": "Find portfolio investors (owners of 2+ properties)",
        "description": "Returns portfolio owners ranked by property count and total assessed value. Useful for finding institutional buyers, small landlords, or specific investor families.",
        "tags": [
          "Deals"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "min_properties",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 2
            },
            "description": "Minimum properties owned."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "NC"
            },
            "description": "2-letter owner mailing state filter."
          },
          {
            "name": "min_value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Minimum total portfolio assessed value, USD."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Owner name substring search."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Portfolio owners returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PortfolioOwner"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhook endpoints",
        "description": "Returns all webhook endpoints for the calling account, plus the per-tier quota.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook endpoints returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhooks": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    },
                    "quota": {
                      "$ref": "#/components/schemas/WebhookQuota"
                    },
                    "tier": {
                      "type": "string",
                      "enum": [
                        "free",
                        "starter",
                        "pro",
                        "scale",
                        "api_100k"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create a webhook endpoint",
        "description": "Creates a new webhook subscription. The returned `secret` is shown ONCE \u2014 store it server-side and use it to verify every incoming delivery via the `X-PropRaven-Signature` header (HMAC-SHA256 over `<unix_ms>.<raw_body>`). Reject deliveries where `|now - t| > 5min`.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created. Response includes the one-time secret.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreated"
                }
              }
            }
          },
          "400": {
            "description": "Invalid url, event_types, filter_kind, or filter_value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Tier quota reached or feature gated. Body includes upgrade guidance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "One or more event types are accepted by the API but not yet emitted by the scanner. Only `parcel.sold` is live in v1.0.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/webhooks/{id}": {
      "get": {
        "operationId": "getWebhook",
        "summary": "Get a single webhook endpoint",
        "description": "Returns the full endpoint record (without the secret).",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Webhook endpoint ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook endpoint returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Soft-disable a webhook endpoint",
        "description": "Marks the endpoint inactive. Delivery history is preserved. The endpoint can no longer receive new events but past deliveries remain queryable via the deliveries route.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Webhook endpoint ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook disabled.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "summary": "Recent delivery attempts for a webhook",
        "description": "Returns the last 100 delivery attempts for an endpoint \u2014 useful for debugging signature mismatches, retry visibility, and dead-letter inspection.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Webhook endpoint ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Recent deliveries returned (max 100, newest first).",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/search/autocomplete": {
      "get": {
        "operationId": "searchAutocomplete",
        "summary": "Address / place / parcel autocomplete",
        "description": "Fast prefix-matched autocomplete: returns cities/places, matching parcels, and Mapbox-geocoded addresses for the prefix. Three independent tiers run in parallel with per-tier timeouts so a slow DB query never blocks fast Mapbox results. Use for type-ahead UIs and address entry; for full-detail lookup use parcel lookup.",
        "tags": [
          "Search"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            },
            "description": "Search prefix. Minimum 2 chars."
          }
        ],
        "responses": {
          "200": {
            "description": "Autocomplete results returned. Empty arrays if `q` is too short or yields no matches.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AutocompleteResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/search/export": {
      "get": {
        "operationId": "exportSearchResults",
        "summary": "Export search results as CSV",
        "description": "Returns up to 10,000 search-matched parcels as a CSV download. Accepts the same geographic + attribute filters as POST /api/v1/search. Designed for spreadsheet / Excel workflows; for programmatic ingestion, use the JSON search endpoint and paginate.",
        "tags": [
          "Search"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "north",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "description": "Bounding box: north latitude."
          },
          {
            "name": "south",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "description": "Bounding box: south latitude."
          },
          {
            "name": "east",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "description": "Bounding box: east longitude."
          },
          {
            "name": "west",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "description": "Bounding box: west longitude."
          },
          {
            "name": "zoningCategories",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-delimited zoning categories."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "address",
                "city",
                "state",
                "owner_name",
                "total_assessed_value",
                "zoning",
                "year_built",
                "lot_size_acres",
                "ownership_type"
              ]
            },
            "description": "Sort column."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort direction."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1000
            },
            "description": "Row cap. Hard max 10,000."
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file. First row is a header. `Content-Disposition` is set to `attachment`.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/search/full": {
      "get": {
        "operationId": "fullSearch",
        "summary": "Full paginated text + attribute search",
        "description": "Paginated search across the parcel search index by free-text query (`q`) and optional field/state/city filters. Distinct from POST /api/v1/search which is geo-bounded; this endpoint is text-anchored and works without a bounding box. Returns 50/page by default, 200 max.",
        "tags": [
          "Search"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            },
            "description": "Search query. Min 2 chars."
          },
          {
            "name": "field",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "address",
                "owner_name",
                "city"
              ],
              "default": "all"
            },
            "description": "Field to match against."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 2
            },
            "description": "2-letter state filter."
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "City filter."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "1-indexed page number."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Page size, max 200."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "address",
                "city",
                "state",
                "owner_name",
                "total_value",
                "year_built"
              ],
              "default": "address"
            },
            "description": "Sort column."
          },
          {
            "name": "dir",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "asc"
            },
            "description": "Sort direction."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated search results.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullSearchResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/geojson": {
      "get": {
        "operationId": "getParcelGeoJSON",
        "summary": "Parcel polygons as GeoJSON for a bounding box",
        "description": "Returns parcel polygons inside a bounding box as a GeoJSON FeatureCollection. Only served at zoom \u2265 14 to limit data volume \u2014 coarser bbox returns an empty collection. Each feature's properties include parcel_id, county_fips, owner_name, assessed value, and basic attributes for rendering popups.",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bbox",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^-?[0-9.]+,-?[0-9.]+,-?[0-9.]+,-?[0-9.]+$"
            },
            "description": "Bounding box `west,south,east,north`."
          },
          {
            "name": "zoom",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Map zoom level. Below 14 returns an empty collection."
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection. Empty `features` array if zoom < 14 or bbox is too wide (>0.15\u00b0 span).",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParcelGeoJSON"
                }
              }
            }
          },
          "400": {
            "description": "Invalid bbox.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/{id}/report": {
      "get": {
        "operationId": "getParcelReport",
        "summary": "Comprehensive parcel report",
        "description": "Returns the full canonical parcel record plus every enrichment: UCC liens, comparable sales, owner portfolio context, permits, deeds, hazard composite. This is the single most data-dense endpoint per parcel \u2014 designed for due-diligence and underwriting workflows. Heavier than parcels/{id}; cache aggressively when serving UIs.",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Parcel ID. Composite `county_fips:parcel_id` or county-local id when `county_fips` query param is provided."
          },
          {
            "name": "county_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37183"
            },
            "description": "5-digit county FIPS. Strongly recommended when passing a county-local id."
          }
        ],
        "responses": {
          "200": {
            "description": "Comprehensive report.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParcelReport"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/parcels/{id}/traffic-history": {
      "get": {
        "operationId": "getParcelTrafficHistory",
        "summary": "Nearest traffic station + AADT history",
        "description": "Finds the AADT (annual average daily traffic) station nearest to the given coordinates and returns its historical time series plus 3/5/7-year CAGRs. Useful for retail / CRE site selection. Search radius ~2 miles; returns empty data if no station is in range.",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Parcel ID (used for context only; the actual nearest-station search is by lat/lng)."
          },
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "description": "Latitude."
          },
          {
            "name": "lng",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "description": "Longitude."
          }
        ],
        "responses": {
          "200": {
            "description": "Nearest station data + historical AADT.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrafficStationHistory"
                }
              }
            }
          },
          "400": {
            "description": "lat / lng required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/market/counties/{fips}": {
      "get": {
        "operationId": "getCountyDetail",
        "summary": "Detailed view for a single county",
        "description": "Returns the full county profile: quarterly market stats (sale count, median price, YoY change, days on market), affordability index by year, parcel summary (count, avg assessed value), and flip activity. Use for county-detail dashboards.",
        "tags": [
          "Market"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "fips",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{5}$"
            },
            "description": "5-digit county FIPS code."
          }
        ],
        "responses": {
          "200": {
            "description": "County detail returned.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountyDetail"
                }
              }
            }
          },
          "400": {
            "description": "Invalid FIPS code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/market/flips": {
      "get": {
        "operationId": "getMarketFlips",
        "summary": "Flip-activity summary grouped by county",
        "description": "Aggregated flip activity per county: count, average ROI, average hold days, total profit. Use for surfacing the hottest flip markets. Differs from /api/v1/deals/flips which returns the underlying transactions.",
        "tags": [
          "Market"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "state_fips",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "37"
            },
            "description": "2-digit state FIPS filter."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            },
            "description": "Page size, max 500."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset."
          }
        ],
        "responses": {
          "200": {
            "description": "Flip summary by county.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MarketFlipsRow"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/owners/{name}/transactions": {
      "get": {
        "operationId": "getOwnerTransactions",
        "summary": "Recorded deed transactions for an owner",
        "description": "Returns up to 100 most-recent deed events where the named owner is either grantor or grantee. Useful for building an owner's transaction timeline across their portfolio.",
        "tags": [
          "Owners"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "BLACKROCK FUND ADVISORS"
            },
            "description": "Owner name. URL-encoded; case-insensitive trimmed match against grantor / grantee."
          }
        ],
        "responses": {
          "200": {
            "description": "Transactions returned. Newest first. Capped at 100.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnerTransaction"
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    },
    "/api/v1/account/usage": {
      "get": {
        "operationId": "getAccountUsage",
        "summary": "Current-period usage and quota",
        "description": "Returns the calling key's current-period API usage, included allotment, remaining calls, configured per-minute and per-day rate limits, and the hard-cap status. Per-user (all of a user's API keys roll up to the same monthly counter, since they share a Stripe subscription).",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage report.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountUsage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceeded"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "pz_*",
        "description": "API key with pz_ prefix. Pass as: Authorization: Bearer pz_your_api_key"
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Maximum number of requests allowed in the current window.",
        "schema": {
          "type": "integer",
          "example": 1000
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Number of requests remaining in the current window.",
        "schema": {
          "type": "integer",
          "example": 997
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp (seconds) when the rate limit window resets.",
        "schema": {
          "type": "integer",
          "example": 1711670400
        }
      }
    },
    "schemas": {
      "Parcel": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string",
            "description": "5-digit county FIPS code.",
            "example": "37183"
          },
          "parcel_id": {
            "type": "string",
            "description": "County-assigned parcel identifier.",
            "example": "0012345"
          },
          "state_fips": {
            "type": "string",
            "example": "37"
          },
          "state_abbr": {
            "type": "string",
            "example": "NC"
          },
          "county_name": {
            "type": "string",
            "example": "Wake"
          },
          "address": {
            "type": "string",
            "example": "123 Main St"
          },
          "city": {
            "type": "string",
            "example": "Raleigh"
          },
          "zip": {
            "type": "string",
            "example": "27601"
          },
          "owner_name": {
            "type": "string",
            "example": "SMITH JOHN A"
          },
          "owner_type": {
            "type": "string",
            "enum": [
              "individual",
              "corporation",
              "llc",
              "trust",
              "government",
              "other"
            ],
            "example": "individual"
          },
          "mailing_address": {
            "type": "string",
            "nullable": true,
            "example": "456 Oak Ave, Durham, NC 27701"
          },
          "assessed_value": {
            "type": "number",
            "nullable": true,
            "example": 285000
          },
          "land_value": {
            "type": "number",
            "nullable": true,
            "example": 95000
          },
          "improvement_value": {
            "type": "number",
            "nullable": true,
            "example": 190000
          },
          "market_value": {
            "type": "number",
            "nullable": true,
            "example": 310000
          },
          "acreage": {
            "type": "number",
            "nullable": true,
            "example": 0.35
          },
          "year_built": {
            "type": "integer",
            "nullable": true,
            "example": 1998
          },
          "zoning": {
            "type": "string",
            "nullable": true,
            "example": "R-6"
          },
          "zoning_category": {
            "type": "string",
            "nullable": true,
            "enum": [
              "residential",
              "commercial",
              "industrial",
              "agricultural",
              "mixed",
              "other"
            ],
            "example": "residential"
          },
          "land_use": {
            "type": "string",
            "nullable": true,
            "example": "Single Family Residential"
          },
          "latitude": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "example": 35.7796
          },
          "longitude": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "example": -78.6382
          },
          "last_sale_date": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "example": "2021-06-15"
          },
          "last_sale_price": {
            "type": "number",
            "nullable": true,
            "example": 295000
          },
          "absentee_owner": {
            "type": "boolean",
            "example": false
          },
          "crime_score": {
            "type": "number",
            "nullable": true,
            "description": "Crime score from 0 (low) to 100 (high).",
            "example": 32
          },
          "deal_score": {
            "type": "number",
            "nullable": true,
            "description": "Composite deal opportunity score from 0 to 100.",
            "example": 72
          }
        }
      },
      "Owner": {
        "type": "object",
        "properties": {
          "owner_name": {
            "type": "string",
            "example": "BLACKROCK FUND ADVISORS"
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "individual",
              "corporation",
              "llc",
              "trust",
              "government",
              "other"
            ],
            "example": "corporation"
          },
          "property_count": {
            "type": "integer",
            "example": 142
          },
          "total_assessed_value": {
            "type": "number",
            "example": 85000000
          },
          "states": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "NC",
              "SC",
              "GA",
              "FL"
            ]
          }
        }
      },
      "Permit": {
        "type": "object",
        "properties": {
          "permit_number": {
            "type": "string",
            "example": "BLD-2024-00123"
          },
          "type": {
            "type": "string",
            "example": "Building"
          },
          "status": {
            "type": "string",
            "enum": [
              "issued",
              "pending",
              "approved",
              "expired",
              "completed",
              "denied"
            ],
            "example": "issued"
          },
          "description": {
            "type": "string",
            "example": "New single family dwelling"
          },
          "issued_date": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "example": "2024-03-15"
          },
          "estimated_cost": {
            "type": "number",
            "nullable": true,
            "example": 350000
          },
          "contractor": {
            "type": "string",
            "nullable": true,
            "example": "ABC Construction LLC"
          }
        }
      },
      "Deed": {
        "type": "object",
        "properties": {
          "document_number": {
            "type": "string",
            "example": "2024-012345"
          },
          "recording_date": {
            "type": "string",
            "format": "date",
            "example": "2024-06-20"
          },
          "sale_date": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "example": "2024-06-15"
          },
          "sale_price": {
            "type": "number",
            "nullable": true,
            "example": 295000
          },
          "grantor_name": {
            "type": "string",
            "example": "JONES ROBERT B"
          },
          "grantee_name": {
            "type": "string",
            "example": "SMITH JOHN A"
          },
          "deed_type": {
            "type": "string",
            "nullable": true,
            "example": "Warranty Deed"
          }
        }
      },
      "RiskAssessment": {
        "type": "object",
        "properties": {
          "flood_zone": {
            "type": "object",
            "properties": {
              "zone": {
                "type": "string",
                "nullable": true,
                "description": "FEMA flood zone designation.",
                "example": "X"
              },
              "in_floodplain": {
                "type": "boolean",
                "example": false
              },
              "description": {
                "type": "string",
                "nullable": true,
                "example": "Area of minimal flood hazard"
              }
            }
          },
          "wildfire": {
            "type": "object",
            "properties": {
              "risk_class": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "low",
                  "moderate",
                  "high",
                  "very_high",
                  "extreme"
                ],
                "example": "low"
              },
              "burn_probability": {
                "type": "number",
                "nullable": true,
                "description": "Annual burn probability as a decimal.",
                "example": 0.0002
              }
            }
          },
          "air_quality": {
            "type": "object",
            "properties": {
              "median_aqi": {
                "type": "number",
                "nullable": true,
                "description": "Median Air Quality Index value.",
                "example": 42
              },
              "category": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "good",
                  "moderate",
                  "unhealthy_sensitive",
                  "unhealthy",
                  "very_unhealthy",
                  "hazardous"
                ],
                "example": "good"
              }
            }
          },
          "crime": {
            "type": "object",
            "properties": {
              "score": {
                "type": "number",
                "nullable": true,
                "description": "Crime score from 0 (low) to 100 (high).",
                "example": 32
              },
              "tier": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "very_low",
                  "low",
                  "moderate",
                  "high",
                  "very_high"
                ],
                "example": "low"
              },
              "trend": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "decreasing",
                  "stable",
                  "increasing"
                ],
                "example": "stable"
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Error code.",
            "example": "not_found"
          },
          "message": {
            "type": "string",
            "description": "Human-readable error description.",
            "example": "The requested parcel was not found."
          }
        }
      },
      "Contractor": {
        "type": "object",
        "properties": {
          "contractor_name_normalized": {
            "type": "string",
            "example": "ABC CONSTRUCTION LLC"
          },
          "contractor_license": {
            "type": [
              "string",
              "null"
            ]
          },
          "permit_count": {
            "type": "integer",
            "example": 1240
          },
          "jurisdiction_count": {
            "type": "integer",
            "example": 12
          },
          "state_count": {
            "type": "integer",
            "example": 3
          },
          "county_count": {
            "type": "integer",
            "example": 8
          },
          "total_permit_value": {
            "type": "number",
            "example": 184500000
          },
          "avg_permit_value": {
            "type": "number",
            "example": 148790
          },
          "first_permit_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "last_permit_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "active_years": {
            "type": [
              "number",
              "null"
            ],
            "example": 12.5
          },
          "top_permit_types": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "states_list": {
            "type": [
              "string",
              "null"
            ],
            "description": "Comma-delimited 2-letter state codes."
          },
          "contractor_rank": {
            "type": "integer",
            "description": "National rank, 1 = highest activity."
          }
        }
      },
      "EntityOwnedParcel": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string"
          },
          "state_fips": {
            "type": "string"
          },
          "parcel_id": {
            "type": "string"
          },
          "owner_name": {
            "type": "string"
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "LLC",
              "CORP",
              "TRUST",
              "LP",
              "LTD",
              "ASSOCIATION",
              "OTHER_ENTITY"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "zip": {
            "type": [
              "string",
              "null"
            ]
          },
          "total_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "zoning": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "EntityAggregate": {
        "type": "object",
        "properties": {
          "owner_name": {
            "type": "string"
          },
          "entity_type": {
            "type": "string"
          },
          "parcel_count": {
            "type": "integer"
          },
          "total_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "states_arr": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "EntitySummary": {
        "type": "object",
        "properties": {
          "total_entities": {
            "type": "integer"
          },
          "total_parcels": {
            "type": "integer"
          },
          "llc_count": {
            "type": "integer"
          },
          "corp_count": {
            "type": "integer"
          },
          "trust_count": {
            "type": "integer"
          },
          "lp_count": {
            "type": "integer"
          }
        }
      },
      "HighLandRatioParcel": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string"
          },
          "state_fips": {
            "type": "string"
          },
          "parcel_id": {
            "type": "string"
          },
          "owner_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "land_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "improvement_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "total_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "land_improvement_ratio": {
            "type": "number",
            "example": 4.2,
            "description": "land / improvement, higher = more redevelopment potential."
          },
          "zoning": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Lender": {
        "type": "object",
        "properties": {
          "lender_name_normalized": {
            "type": "string",
            "example": "WELLS FARGO BANK NA"
          },
          "mortgage_count": {
            "type": "integer"
          },
          "total_mortgage_volume": {
            "type": [
              "number",
              "null"
            ]
          },
          "avg_mortgage_amount": {
            "type": [
              "number",
              "null"
            ]
          },
          "median_mortgage_amount": {
            "type": [
              "number",
              "null"
            ]
          },
          "county_count": {
            "type": "integer"
          },
          "state_count": {
            "type": "integer"
          },
          "states_list": {
            "type": [
              "string",
              "null"
            ]
          },
          "first_mortgage_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "last_mortgage_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "lender_rank": {
            "type": "integer",
            "description": "National rank, 1 = highest volume."
          }
        }
      },
      "LongHoldParcel": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string"
          },
          "state_fips": {
            "type": "string"
          },
          "parcel_id": {
            "type": "string"
          },
          "owner_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "zip": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_sale_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "years_held": {
            "type": "number"
          },
          "hold_tier": {
            "type": "string",
            "enum": [
              "10-15yr",
              "15-20yr",
              "20-30yr",
              "30yr+"
            ]
          },
          "total_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "MarketSummary": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string"
          },
          "state_fips": {
            "type": "string"
          },
          "county_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "year": {
            "type": "integer"
          },
          "sale_count": {
            "type": "integer"
          },
          "median_sale_price": {
            "type": [
              "number",
              "null"
            ]
          },
          "avg_sale_price": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "AffordabilityRow": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string"
          },
          "state_fips": {
            "type": "string"
          },
          "county_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "year": {
            "type": "integer"
          },
          "median_sale_price": {
            "type": [
              "number",
              "null"
            ]
          },
          "median_household_income": {
            "type": [
              "number",
              "null"
            ]
          },
          "price_to_income_ratio": {
            "type": [
              "number",
              "null"
            ]
          },
          "monthly_payment_estimate": {
            "type": [
              "number",
              "null"
            ]
          },
          "pct_income_for_housing": {
            "type": [
              "number",
              "null"
            ]
          },
          "affordability_rating": {
            "type": "string",
            "enum": [
              "AFFORDABLE",
              "MODERATE",
              "EXPENSIVE",
              "VERY_EXPENSIVE"
            ]
          }
        }
      },
      "PortfolioOwner": {
        "type": "object",
        "properties": {
          "owner_name_normalized": {
            "type": "string"
          },
          "owner_state": {
            "type": [
              "string",
              "null"
            ]
          },
          "property_count": {
            "type": "integer"
          },
          "state_count": {
            "type": "integer"
          },
          "county_count": {
            "type": "integer"
          },
          "total_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "avg_assessed_value": {
            "type": [
              "number",
              "null"
            ]
          },
          "total_acreage": {
            "type": [
              "number",
              "null"
            ]
          },
          "states_list": {
            "type": [
              "string",
              "null"
            ]
          },
          "portfolio_rank": {
            "type": "integer",
            "description": "National rank, 1 = largest portfolio."
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Customer endpoint. Must be https://."
          },
          "secret_prefix": {
            "type": "string",
            "description": "First 14 chars of the secret (whsec_ + 8 hex). Use to identify the webhook in your dashboard; full secret is shown only at create time."
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "parcel.sold",
                "parcel.permit_filed",
                "parcel.owner_changed"
              ]
            }
          },
          "filter_kind": {
            "type": "string",
            "enum": [
              "parcel_ids",
              "state_fips",
              "county_fips"
            ]
          },
          "filter_value": {
            "$ref": "#/components/schemas/WebhookFilter"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "disabled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "disabled_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "deliveries_attempted": {
            "type": "integer"
          },
          "deliveries_succeeded": {
            "type": "integer"
          },
          "last_delivery_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_success_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "WebhookFilter": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "parcel_ids"
            ],
            "properties": {
              "parcel_ids": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "minItems": 1,
                "maxItems": 1000,
                "description": "Composite parcel IDs to subscribe to. 1\u20131000 IDs."
              }
            }
          },
          {
            "type": "object",
            "required": [
              "state_fips"
            ],
            "properties": {
              "state_fips": {
                "type": "string",
                "pattern": "^[0-9]{2}$",
                "description": "2-digit state FIPS \u2014 subscribe to all parcels in this state."
              }
            }
          },
          {
            "type": "object",
            "required": [
              "state_fips",
              "county_fips"
            ],
            "properties": {
              "state_fips": {
                "type": "string",
                "pattern": "^[0-9]{2}$"
              },
              "county_fips": {
                "type": "string",
                "pattern": "^[0-9]{3}$",
                "description": "3-digit county FIPS (within the state) \u2014 subscribe to all parcels in this county."
              }
            }
          }
        ],
        "description": "Shape varies with filter_kind. parcel_ids: explicit list. state_fips: all parcels in a state. county_fips: all parcels in a county within a state."
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "event_types",
          "filter_kind",
          "filter_value"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Customer endpoint. https:// only."
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "parcel.sold",
                "parcel.permit_filed",
                "parcel.owner_changed"
              ]
            },
            "minItems": 1,
            "description": "Event types to subscribe to. NOTE: only parcel.sold is live in v1.0; others 501."
          },
          "filter_kind": {
            "type": "string",
            "enum": [
              "parcel_ids",
              "state_fips",
              "county_fips"
            ]
          },
          "filter_value": {
            "$ref": "#/components/schemas/WebhookFilter"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "Optional human-readable label for your dashboard."
          }
        }
      },
      "WebhookCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "required": [
              "secret",
              "hint"
            ],
            "properties": {
              "secret": {
                "type": "string",
                "description": "**Shown once.** Copy and store server-side immediately. Used to sign every outgoing delivery."
              },
              "hint": {
                "type": "string",
                "description": "Signature-verification reminder."
              }
            }
          }
        ]
      },
      "WebhookQuota": {
        "type": "object",
        "properties": {
          "maxEndpoints": {
            "type": "integer",
            "description": "Max simultaneous active webhook endpoints on this tier."
          },
          "maxEventsPerDay": {
            "type": "integer",
            "description": "Max event deliveries per UTC day on this tier."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event_id": {
            "type": "string",
            "description": "Deterministic event identifier \u2014 sha256(source || pk || event_type). Idempotent re-deliveries share this."
          },
          "event_type": {
            "type": "string",
            "enum": [
              "parcel.sold",
              "parcel.permit_filed",
              "parcel.owner_changed"
            ]
          },
          "event_occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "in_flight",
              "succeeded",
              "failed",
              "dead_lettered"
            ]
          },
          "attempts": {
            "type": "integer"
          },
          "last_attempt_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "next_attempt_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_response_status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "last_response_body": {
            "type": [
              "string",
              "null"
            ],
            "description": "Truncated to ~1KB."
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "dead_lettered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ParcelSoldEvent": {
        "type": "object",
        "required": [
          "event_type",
          "event_id",
          "occurred_at",
          "delivery_attempt",
          "parcel_id",
          "state_fips",
          "county_fips"
        ],
        "properties": {
          "event_type": {
            "type": "string",
            "const": "parcel.sold"
          },
          "event_id": {
            "type": "string",
            "description": "Deterministic. Use for idempotency."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "delivery_attempt": {
            "type": "integer",
            "description": "Starts at 1; increments on retry."
          },
          "parcel_id": {
            "type": "string",
            "description": "Composite county_fips:parcel_id."
          },
          "state_fips": {
            "type": "string"
          },
          "county_fips": {
            "type": "string"
          },
          "sale_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "sale_price_usd": {
            "type": [
              "number",
              "null"
            ],
            "description": "May be null in non-disclosure states (KS, MS, TX, UT, WY, etc.)."
          },
          "grantor": {
            "type": [
              "string",
              "null"
            ]
          },
          "grantee": {
            "type": [
              "string",
              "null"
            ]
          },
          "recorded_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "source_run_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "PropRaven ingest run that surfaced this event."
          }
        }
      },
      "AutocompleteResult": {
        "type": "object",
        "properties": {
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutocompleteLocation"
            }
          },
          "parcels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutocompleteParcel"
            }
          },
          "addresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AutocompleteAddress"
            }
          }
        }
      },
      "AutocompleteLocation": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Raleigh, 37"
          },
          "type": {
            "type": "string",
            "const": "city"
          },
          "state": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "lat": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "lng": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "parcel_count": {
            "type": "integer"
          }
        }
      },
      "AutocompleteParcel": {
        "type": "object",
        "properties": {
          "parcel_id": {
            "type": "string"
          },
          "county_fips": {
            "type": "string"
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string",
            "const": "parcel"
          }
        }
      },
      "AutocompleteAddress": {
        "type": "object",
        "description": "Mapbox-geocoded address suggestion. Use to disambiguate user input before calling /api/v1/lookup or /api/v1/parcels/{id}.",
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "const": "address"
          },
          "lat": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "lng": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          }
        }
      },
      "FullSearchResult": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Parcel"
            }
          },
          "total": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          }
        }
      },
      "ParcelGeoJSON": {
        "type": "object",
        "description": "GeoJSON FeatureCollection of parcel polygons. Each feature's properties carry the basic parcel summary for popup rendering.",
        "properties": {
          "type": {
            "type": "string",
            "const": "FeatureCollection"
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ParcelGeoFeature"
            }
          }
        }
      },
      "ParcelGeoFeature": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "const": "Feature"
          },
          "geometry": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "Polygon"
              },
              "coordinates": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                },
                "description": "GeoJSON polygon coordinate rings: outer ring first, then any inner rings."
              }
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "parcel_id": {
                "type": "string"
              },
              "county_fips": {
                "type": "string"
              },
              "address": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "city": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "state": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "owner_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "total_assessed_value": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "property_type": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "year_built": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "latitude": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double"
              },
              "longitude": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double"
              }
            }
          }
        }
      },
      "ParcelReport": {
        "type": "object",
        "description": "Comprehensive parcel report \u2014 every PropRaven data point joined per parcel. Subsections are populated on a best-effort basis; missing data is omitted rather than nulled.",
        "properties": {
          "parcel": {
            "$ref": "#/components/schemas/Parcel"
          },
          "ucc_liens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UccLien"
            }
          },
          "comparable_sales": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComparableSale"
            }
          },
          "permits": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Permit"
            }
          },
          "deeds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Deed"
            }
          },
          "risk": {
            "$ref": "#/components/schemas/RiskAssessment"
          }
        }
      },
      "UccLien": {
        "type": "object",
        "properties": {
          "filing_id": {
            "type": "string"
          },
          "debtor_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "secured_party": {
            "type": [
              "string",
              "null"
            ]
          },
          "filing_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "lapse_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "filing_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "match_method": {
            "type": [
              "string",
              "null"
            ]
          },
          "match_confidence": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1
          }
        }
      },
      "ComparableSale": {
        "type": "object",
        "properties": {
          "comp_parcel_id": {
            "type": "string"
          },
          "comp_sale_price": {
            "type": [
              "number",
              "null"
            ]
          },
          "comp_sale_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "comp_sqft": {
            "type": [
              "integer",
              "null"
            ]
          },
          "comp_beds": {
            "type": [
              "integer",
              "null"
            ]
          },
          "comp_baths": {
            "type": [
              "number",
              "null"
            ]
          },
          "similarity_score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1
          },
          "distance_miles": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "TrafficStationHistory": {
        "type": "object",
        "properties": {
          "station": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "station_id": {
                "type": "string"
              },
              "route_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "functional_class": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "aadt_current": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Most recent AADT count."
              },
              "aadt_year": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cagr_3yr": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "cagr_5yr": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "cagr_7yr": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "latitude": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double"
              },
              "longitude": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double"
              }
            }
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "year": {
                  "type": "integer"
                },
                "aadt": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            },
            "description": "Year-keyed historical counts (newest last)."
          }
        }
      },
      "CountyDetail": {
        "type": "object",
        "properties": {
          "market_stats": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "county_fips": {
                  "type": "string"
                },
                "state_fips": {
                  "type": "string"
                },
                "quarter": {
                  "type": "string",
                  "example": "2025Q4"
                },
                "sale_count": {
                  "type": "integer"
                },
                "median_sale_price": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "avg_sale_price": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "total_volume": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "price_yoy_pct": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "avg_dom": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Average days on market."
                }
              }
            }
          },
          "affordability": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffordabilityRow"
            }
          },
          "parcel_summary": {
            "type": "object",
            "properties": {
              "parcel_count": {
                "type": "integer"
              },
              "avg_assessed_value": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "flip_summary": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "flip_count": {
                "type": "integer"
              },
              "avg_roi": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "avg_hold_days": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "total_profit": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          }
        }
      },
      "MarketFlipsRow": {
        "type": "object",
        "properties": {
          "county_fips": {
            "type": "string"
          },
          "flip_count": {
            "type": "integer"
          },
          "avg_roi": {
            "type": [
              "number",
              "null"
            ],
            "description": "Average profit percentage (e.g. 0.18 = 18%)."
          },
          "avg_hold_days": {
            "type": [
              "number",
              "null"
            ]
          },
          "total_profit": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "OwnerTransaction": {
        "type": "object",
        "properties": {
          "document_number": {
            "type": "string"
          },
          "recording_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "sale_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "document_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recorded document type (Warranty Deed, Quit Claim, etc.)."
          },
          "sale_price": {
            "type": [
              "number",
              "null"
            ],
            "description": "USD. Null when state is non-disclosure."
          },
          "grantor_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "grantee_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "property_address": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AccountUsage": {
        "type": "object",
        "properties": {
          "tier": {
            "type": "string",
            "enum": [
              "free",
              "starter",
              "pro",
              "scale",
              "api_100k"
            ]
          },
          "period": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "end": {
                "type": "string",
                "format": "date-time"
              },
              "label": {
                "type": "string",
                "example": "2026-05"
              }
            }
          },
          "calls_included": {
            "type": "integer",
            "description": "Plan allotment for the current period."
          },
          "calls_used": {
            "type": "integer"
          },
          "calls_remaining": {
            "type": "integer"
          },
          "hard_capped": {
            "type": "boolean",
            "description": "Whether further calls will be hard-rejected vs allowed-and-billed."
          },
          "rate_limit": {
            "type": "object",
            "properties": {
              "per_minute": {
                "type": "integer"
              },
              "per_day": {
                "type": "integer"
              }
            }
          }
        }
      },
      "ParcelOwnerChangedEvent": {
        "type": "object",
        "required": [
          "event_type",
          "event_id",
          "occurred_at",
          "delivery_attempt",
          "parcel_id",
          "state_fips",
          "county_fips"
        ],
        "properties": {
          "event_type": {
            "type": "string",
            "const": "parcel.owner_changed"
          },
          "event_id": {
            "type": "string",
            "description": "Deterministic. Use for idempotency."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "delivery_attempt": {
            "type": "integer",
            "description": "Starts at 1; increments on retry."
          },
          "parcel_id": {
            "type": "string",
            "description": "Composite county_fips:parcel_id."
          },
          "state_fips": {
            "type": "string"
          },
          "county_fips": {
            "type": "string"
          },
          "recorded_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "document_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Deed/document classification (e.g., Warranty Deed, Quitclaim Deed, Trust Transfer)."
          },
          "document_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "prior_owner": {
            "type": [
              "string",
              "null"
            ],
            "description": "Grantor on the recorded deed."
          },
          "new_owner": {
            "type": [
              "string",
              "null"
            ],
            "description": "Grantee on the recorded deed."
          },
          "is_sale": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "True when the transfer is a real sale (price > 0, arm's-length). When true, subscribers to parcel.sold ALSO receive that event."
          },
          "source_run_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "PropRaven ingest run that surfaced this event."
          }
        }
      },
      "ParcelPermitFiledEvent": {
        "type": "object",
        "required": [
          "event_type",
          "event_id",
          "occurred_at",
          "delivery_attempt",
          "parcel_id",
          "state_fips",
          "county_fips",
          "permit_id"
        ],
        "properties": {
          "event_type": {
            "type": "string",
            "const": "parcel.permit_filed"
          },
          "event_id": {
            "type": "string",
            "description": "Deterministic. Use for idempotency."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "delivery_attempt": {
            "type": "integer",
            "description": "Starts at 1; increments on retry."
          },
          "parcel_id": {
            "type": "string",
            "description": "Composite county_fips:parcel_id."
          },
          "state_fips": {
            "type": "string"
          },
          "county_fips": {
            "type": "string"
          },
          "permit_id": {
            "type": "string",
            "description": "PropRaven internal permit id (stable across re-ingests)."
          },
          "permit_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Jurisdiction-issued permit number."
          },
          "permit_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Building, electrical, roofing, demolition, etc."
          },
          "permit_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Filed, issued, in_review, final, expired, withdrawn."
          },
          "filed_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "issued_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "estimated_cost": {
            "type": [
              "number",
              "null"
            ],
            "description": "Declared job cost in USD."
          },
          "contractor_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "contractor_license": {
            "type": [
              "string",
              "null"
            ]
          },
          "applicant_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "jurisdiction_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "PropRaven jurisdiction id; join to /v1/jurisdictions."
          },
          "source_run_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "PropRaven ingest run that surfaced this event."
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Invalid or missing API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "unauthorized",
              "message": "Invalid API key. Keys must use the pz_ prefix."
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested resource was not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "not_found",
              "message": "The requested resource was not found."
            }
          }
        }
      },
      "RateLimitExceeded": {
        "description": "Rate limit exceeded.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "rate_limit_exceeded",
              "message": "Rate limit exceeded. Please retry after the reset time indicated in the X-RateLimit-Reset header."
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Parcels",
      "description": "Parcel lookup, owner details, permits, deeds, and risk data."
    },
    {
      "name": "Search",
      "description": "Geographic and filtered parcel search."
    },
    {
      "name": "Coverage",
      "description": "Data coverage statistics."
    },
    {
      "name": "Deals",
      "description": "Deal sourcing: absentee owners, property flips."
    },
    {
      "name": "Market",
      "description": "County-level market statistics and trends."
    },
    {
      "name": "Owners",
      "description": "Owner search, profiles, and portfolios."
    },
    {
      "name": "Webhooks",
      "description": "Webhook subscriptions and delivery history. Manage which events PropRaven pushes to your endpoints."
    },
    {
      "name": "Account",
      "description": "Account-scoped usage, quota, and key-level reporting."
    }
  ],
  "webhooks": {
    "parcel.sold": {
      "post": {
        "operationId": "onParcelSold",
        "summary": "parcel.sold \u2014 a deed transferring ownership was recorded for a tracked parcel",
        "description": "PropRaven POSTs this event to your endpoint(s) when a new deed transfer is detected on a parcel matching one of your webhook filters. Sign verification: HMAC-SHA256 over `<unix_ms>.<raw_body>`, secret from webhook creation, header `X-PropRaven-Signature: t=<unix_ms>,v1=<sig>`. Reject if the request timestamp is more than 5 minutes from now.",
        "requestBody": {
          "description": "parcel.sold event payload.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParcelSoldEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx status acks the delivery. PropRaven retries non-2xx with exponential backoff; failed deliveries dead-letter after the retry budget is exhausted."
          }
        }
      }
    },
    "parcel.owner_changed": {
      "post": {
        "operationId": "onParcelOwnerChanged",
        "summary": "parcel.owner_changed \u2014 any deed recorded against a tracked parcel (superset of parcel.sold)",
        "description": "PropRaven POSTs this event when a deed of any kind is recorded against a parcel matching one of your webhook filters \u2014 sales, quitclaims, trust transfers, gift deeds, etc. When the transfer is a real sale (price > 0, arm's-length), `is_sale: true` and PropRaven ALSO POSTs a parcel.sold event. Signature verification: HMAC-SHA256 over `<unix_ms>.<raw_body>`, secret from webhook creation, header `X-PropRaven-Signature: t=<unix_ms>,v1=<sig>`. Reject if the request timestamp is more than 5 minutes from now.",
        "requestBody": {
          "description": "parcel.owner_changed event payload.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParcelOwnerChangedEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx status acks the delivery. PropRaven retries non-2xx with exponential backoff; failed deliveries dead-letter after the retry budget is exhausted."
          }
        }
      }
    },
    "parcel.permit_filed": {
      "post": {
        "operationId": "onParcelPermitFiled",
        "summary": "parcel.permit_filed \u2014 a permit was filed (or first observed) for a tracked parcel",
        "description": "PropRaven POSTs this event when a new permit is matched to a parcel matching one of your webhook filters. Fires once per permit per parcel; duplicate filings from the same jurisdiction de-dupe via `permit_id`. Signature verification: HMAC-SHA256 over `<unix_ms>.<raw_body>`, secret from webhook creation, header `X-PropRaven-Signature: t=<unix_ms>,v1=<sig>`. Reject if the request timestamp is more than 5 minutes from now.",
        "requestBody": {
          "description": "parcel.permit_filed event payload.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParcelPermitFiledEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Any 2xx status acks the delivery. PropRaven retries non-2xx with exponential backoff; failed deliveries dead-letter after the retry budget is exhausted."
          }
        }
      }
    }
  }
}
