Florida Property API
Endpoints

Search Sales

Search recorded Florida property sales / deed transfers by county, date range, price range, and use code.

GET /api/v1/sales/search

Coming soon — no data yet. The sales dataset is not yet loaded, so this endpoint returns an empty result set for every query today. The request and response contract documented below is stable and safe to integrate against now; rows will begin appearing as recorded-deed data lands. Track progress on the sales-coverage page.

Search recorded property sales (deed transfers) from county assessment-roll sale data, filterable by county, sale-date range, price range, and use code. Each row carries the deed book/page, instrument number, deed and qualification codes, and grantor/grantee. To get the sale history of one specific parcel, use GET /api/v1/parcels/{id}/sales.

Authentication

All endpoints share the base URL https://api.floridapropertyapi.com/v1. Send your API key in the X-API-Key header.

curl -H "X-API-Key: fpapi_test_..." \
  "https://api.floridapropertyapi.com/v1/sales/search?county=hillsborough&from=2021-01-01&min_price=250000&limit=10"
// JavaScript (fetch)
const res = await fetch(
  "https://api.floridapropertyapi.com/v1/sales/search?county=hillsborough&from=2021-01-01&min_price=250000&limit=10",
  { headers: { "X-API-Key": "fpapi_test_..." } },
);
const body = await res.json();
console.log(body.data);
# Python (requests)
import requests

res = requests.get(
    "https://api.floridapropertyapi.com/v1/sales/search",
    params={"county": "hillsborough", "from": "2021-01-01", "min_price": 250000, "limit": 10},
    headers={"X-API-Key": "fpapi_test_..."},
)
res.raise_for_status()
print(res.json()["data"])

Query Parameters

NameTypeRequiredDefaultDescription
countystring | string[]noCounty slug(s). Repeatable or CSV.
fromdate (YYYY-MM-DD)noOnly sales on/after this date.
todate (YYYY-MM-DD)noOnly sales on/before this date.
min_pricenumbernoMinimum sale price.
max_pricenumbernoMaximum sale price.
use_codestring | string[]noProperty use code(s). Repeatable or CSV.
sortenum (date_newest, date_oldest, price_desc, price_asc)noResult ordering.
limitinteger 1-500no25Page size.
offsetinteger ≥ 0no0Pagination offset.

Response (200)

List envelope { data: SaleHit[], pagination, meta }.

{
  "data": [
    {
      "id": "sale_8fc21a09",
      "county_slug": "hillsborough",
      "county_parcel_id": "192829-5040-001000-0010",
      "sale_date": "2021-04-15",
      "sale_price": 460000,
      "book": "24891",
      "page": "1432",
      "instrument_number": "2021145238",
      "deed_code": "WD",
      "qualification_code": "Q",
      "grantor": "JONES ROBERT L",
      "grantee": "SMITH JOHN A & MARY B"
    }
  ],
  "pagination": { "limit": 25, "offset": 0, "total": 1, "has_more": false },
  "meta": { "request_id": "req_1234567890abcdef12345", "dataset_status": "live" }
}

deed_code and qualification_code are the raw county/FDOR codes (e.g. WD warranty deed, Q qualified sale).

Error Responses

StatusCodeCause
400bad_requestInvalid query parameters.
401unauthorizedMissing or invalid API key.
429rate_limitedRate limit exceeded.
500internal_errorServer error — retry with backoff.

Data Coverage

Sales-history coverage is rolling out county by county as deed-transfer data is imported from each county assessment roll. A county with no sales loaded yet returns an empty data array (never a 404). Parcel-roll coverage is already live statewide across all 67 counties.

Rate Limits

Every /api/v1/* response (including 429) carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers, plus the IETF RateLimit structured field. See Rate Limits for per-tier quotas and backoff guidance.

On this page