API Documentation
Access FairLot's mobile home park lot rent database programmatically. Search parks, retrieve rent data, and build integrations with our REST API.
Overview
The FairLot API provides read-only access to mobile home park data across multiple US states. All responses are JSON. API access requires the Founding Member plan ($33/mo billed annually at $396/yr, or $49/mo billed monthly).
The API covers 600+ parks across Vermont and Nevada, with verified lot rent data for 500+ parks.
Quickstart
Get up and running with the FairLot API in three steps.
- Subscribe to the Founding Member plan Sign up at fairlot.org/#pricing and subscribe to the Founding Member plan ($33/mo billed annually at $396/yr, or $49/mo billed monthly).
-
Generate an API key
From your dashboard, go to Settings > API Keys and create a new key. Your key will start with
fl_live_. -
Make your first request
Try fetching parks with rent data:
curl "https://fairlot.org/api/v1/parks?state=VT&has_rent=true&per_page=5" \ -H "Authorization: Bearer fl_live_your_key_here"import requests resp = requests.get( "https://fairlot.org/api/v1/parks", headers={"Authorization": "Bearer fl_live_your_key_here"}, params={"state": "VT", "has_rent": "true", "per_page": 5} ) data = resp.json() print(f"Found {data['total']} parks") for park in data["parks"]: print(f" {park['name']}: ${park['latest_lot_rent']}/mo")const resp = await fetch( "https://fairlot.org/api/v1/parks?state=VT&has_rent=true&per_page=5", { headers: { "Authorization": "Bearer fl_live_your_key_here" } } ); const data = await resp.json(); console.log(`Found ${data.total} parks`); data.parks.forEach(p => console.log(` ${p.name}: $${p.latest_lot_rent}/mo`) );
Tip: Start with the List Parks endpoint to browse available data, then use Get Park Detail for full rent history on individual parks.
Base URL
All endpoints are under the /api/v1/ prefix. For example, the parks list endpoint is:
GET https://fairlot.org/api/v1/parks
Versioning: The current API version is v1.
The legacy /api/ prefix (without a version) still works and
behaves identically to /api/v1/, but new integrations should
use the versioned URL so they are not affected by future changes.
OpenAPI Specification
A machine-readable OpenAPI 3.1 spec is available for client code generation and tooling integration.
curl "https://fairlot.org/api/v1/openapi.json" | python -m json.toolYou can use this spec with tools like OpenAPI Generator, openapi-ts, or import it directly into Postman or Insomnia.
Authentication
FairLot supports two authentication methods:
1. API Keys (Recommended)
Generate an API key from your dashboard. Include it as a Bearer token:
curl https://fairlot.org/api/v1/parks?state=VT&has_rent=true \
-H "Authorization: Bearer fl_live_your_key_here"2. Session Cookie
For browser-based access, sign in at fairlot.org and the session cookie authenticates automatically.
Plan-Based Access
API responses vary based on your subscription plan. Unauthenticated requests receive limited data with certain fields stripped.
| Capability | Free (Resident) | Founding Member ($33/mo or $49/mo) |
|---|---|---|
| Park list (basic fields) | Yes | Yes (full) |
| Lot rent data | Teaser only (3 per page) | Full (all data points) |
| Owner name, phone, address | No | Yes |
| Park detail endpoint | No (401) | Yes |
| Full rent history | No | Yes |
| CSV export | No | Yes (watermarked) |
| API access | No | Yes |
| Max results per page | 50 | 200 |
| Daily view limit | N/A | 150 parks/day |
Free tier teaser: Unauthenticated requests to
/api/v1/parks will show rent data for up to 3 parks per page,
but only for a limited number of parks per page. All other
rent-related fields are stripped. To access full data, subscribe at
fairlot.org/landing.html#pricing.
Rate Limiting
All API requests are rate-limited using a sliding window algorithm. Rate limit status is returned in response headers on every request.
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the current window |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | Seconds until the rate limit window resets |
| Retry-After | Seconds to wait before retrying (only on 429 responses) |
Rate Limit Tiers
| Tier | Limit | Window | Applies To |
|---|---|---|---|
| Public (unauthenticated) | 60 requests | 60 seconds | IP-based, non-search requests |
| Search (unauthenticated) | 30 requests | 60 seconds | IP-based, requests with search terms |
| Authenticated | 120 requests | 60 seconds | User-based, all authenticated requests |
{
"detail": "Too many requests. Please slow down."
}Pagination
List endpoints return paginated results. Use the page and
per_page query parameters to navigate through results.
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number (1-indexed) |
| per_page | integer | 50 | Results per page (max 50 for free, 200 for Founding Member) |
The response includes total, page, and
per_page fields so you can calculate total pages:
// total_pages = ceil(total / per_page)
{
"total": 238,
"page": 1,
"per_page": 50,
"parks": [...]
}Sorting
Use the sort and dir parameters to control
result ordering on list endpoints.
| Sort Column | Description |
|---|---|
| name | Park name (default) |
| county | County name |
| metro_area | Metro area name |
| lot_count | Number of lots |
| latest_lot_rent | Most recent lot rent amount |
| owner_name | Park owner name |
| fetched_at | Date the record was last updated |
Direction: dir=asc (default) or dir=desc.
The order parameter is accepted as an alias for dir.
Error Handling
The API returns standard HTTP status codes. Error responses include a JSON body with a detail field.
| Status | Meaning | Example |
|---|---|---|
200 |
Success | Request completed |
401 |
Unauthorized | Missing or invalid session cookie |
403 |
Forbidden | Plan upgrade required for this endpoint |
404 |
Not Found | Park ID does not exist |
429 |
Too Many Requests | Rate limit exceeded (check Retry-After header) |
{
"detail": "Authentication required"
}List Parks
Search and filter mobile home parks across all states. Returns a paginated list of parks with optional rent data. This is the primary endpoint for browsing the FairLot database.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| state | string | none | Filter by state abbreviation (e.g., VT, NV) |
| county | string | none | Filter by county name |
| metro_area | string | none | Filter by metro area name |
| min_lots | integer | none | Minimum lot count. Alias: lot_count_min |
| max_lots | integer | none | Maximum lot count. Alias: lot_count_max |
| has_rent | boolean | none | When true, only return parks that have lot rent data |
| q | string | none | Full-text search across park name. Aliases: name, search |
| owner_name | string | none | Filter by park owner name |
| status | string | Approved | Filter by registration status |
| sort | string | name | Sort column (see Sorting) |
| dir | string | asc | Sort direction: asc or desc. Alias: order |
| page | integer | 1 | Page number (1-indexed) |
| per_page | integer | 50 | Results per page (max 50 free, 200 Founding Member) |
curl "https://fairlot.org/api/v1/parks?state=VT&has_rent=true&per_page=3" \
-H "Authorization: Bearer fl_live_your_key_here"import requests
resp = requests.get(
"https://fairlot.org/api/v1/parks",
headers={"Authorization": "Bearer fl_live_your_key_here"},
params={"state": "VT", "has_rent": "true", "per_page": 3}
)
data = resp.json()
print(data["total"], "parks found")const resp = await fetch(
"https://fairlot.org/api/v1/parks?state=VT&has_rent=true&per_page=3",
{ headers: { "Authorization": "Bearer fl_live_your_key_here" } }
);
const data = await resp.json();
console.log(data.total, "parks found");{
"total": 216,
"page": 1,
"per_page": 3,
"parks": [
{
"id": "vt-chittenden-birchwood",
"name": "Birchwood Mobile Home Park",
"county": "Chittenden",
"city": "Essex",
"address": "123 Birchwood Ln",
"state": "VT",
"zip": "05452",
"lot_count": 84,
"owner_name": "Green Mountain Properties LLC",
"status": "Approved",
"phone": "(802) 555-0142",
"metro_area": "Burlington-South Burlington",
"park_size_category": "Medium (50-99)",
"source": "vt_registry",
"fetched_at": "2025-11-15T14:30:00",
"latest_lot_rent": 435.0,
"latest_rent_source": "verified",
"latest_rent_collected_at": "2024-07-01T00:00:00",
"latitude": 44.4918,
"longitude": -73.1148,
"age_restriction": null,
"estimated_occupancy": null
},
// ... more parks
]
}curl "https://fairlot.org/api/v1/parks?state=NV&min_lots=100&sort=latest_lot_rent&dir=desc" \
-H "Authorization: Bearer fl_live_your_key_here"curl "https://fairlot.org/api/v1/parks?q=maple&state=VT" \
-H "Authorization: Bearer fl_live_your_key_here"Get Park Detail
Retrieve detailed information for a single park, including its full rent history. Requires authentication (Founding Member plan). Full rent history is included with the Founding Member plan.
Path Parameters
| Parameter | Type | Description | |
|---|---|---|---|
| park_id | string | required | The unique park identifier (from the list endpoint) |
curl "https://fairlot.org/api/v1/parks/vt-chittenden-birchwood" \
-H "Authorization: Bearer fl_live_your_key_here"import requests
resp = requests.get(
"https://fairlot.org/api/v1/parks/vt-chittenden-birchwood",
headers={"Authorization": "Bearer fl_live_your_key_here"}
)
park = resp.json()
print(park["name"], "-", len(park["lot_rents"]), "rent records")const resp = await fetch(
"https://fairlot.org/api/v1/parks/vt-chittenden-birchwood",
{ headers: { "Authorization": "Bearer fl_live_your_key_here" } }
);
const park = await resp.json();
console.log(park.name, "-", park.lot_rents.length, "rent records");{
"id": "vt-chittenden-birchwood",
"name": "Birchwood Mobile Home Park",
"county": "Chittenden",
"city": "Essex",
"address": "123 Birchwood Ln",
"state": "VT",
"zip": "05452",
"lot_count": 84,
"owner_name": "Green Mountain Properties LLC",
"status": "Approved",
"phone": "(802) 555-0142",
"metro_area": "Burlington-South Burlington",
"park_size_category": "Medium (50-99)",
"source": "vt_registry",
"fetched_at": "2025-11-15T14:30:00",
"latitude": 44.4918,
"longitude": -73.1148,
"owner_address": "456 Main St, Burlington, VT 05401",
"age_restriction": null,
"estimated_occupancy": null,
"latest_lot_rent": 435.0,
"lot_rents": [
{
"lot_rent_monthly": 435.0,
"lot_rent_min": 410.0,
"lot_rent_max": 460.0,
"lot_rent_double_wide": 510.0,
"source": "verified",
"confidence": "high",
"collected_at": "2024-07-01T00:00:00",
"notes": null
},
{
"lot_rent_monthly": 410.0,
"lot_rent_min": 390.0,
"lot_rent_max": 430.0,
"lot_rent_double_wide": 480.0,
"source": "verified",
"confidence": "high",
"collected_at": "2023-07-01T00:00:00",
"notes": null
}
],
"upgrade_hint": null
}
Founding Member plan: The lot_rents array
contains the full rent history for the park. The
upgrade_hint field will be null for
Founding Member subscribers.
{
"detail": "Authentication required"
}{
"detail": "Park not found"
}Aggregate Statistics
Returns aggregate statistics across all parks, broken down by state, county, metro area, and park size category. Includes rent stats (median, average, min, max) per grouping. This endpoint is public but rate-limited.
curl "https://fairlot.org/api/v1/stats"{
"total_parks": 613,
"parks_with_rent_data": 504,
"rent_snapshot": {
"count": 504,
"median": 425.0,
"avg": 468.32,
"min": 125.0,
"max": 1850.0
},
"by_state": [
{
"state": "NV",
"park_count": 375,
"parks_with_rent": 288
},
{
"state": "VT",
"park_count": 238,
"parks_with_rent": 216
}
],
"by_county": [
{
"county": "Chittenden",
"state": "VT",
"park_count": 24,
"rent": {
"count": 19,
"median": 445.0,
"avg": 452.38,
"min": 320.0,
"max": 610.0
}
}
// ... more counties
],
"by_metro": [
{
"metro_area": "Burlington-South Burlington",
"park_count": 28,
"rent": {
"count": 22,
"median": 440.0,
"avg": 448.5,
"min": 310.0,
"max": 610.0
}
}
// ... more metros
],
"by_size_category": [
{
"park_size_category": "Small (1-49)",
"park_count": 1842
},
{
"park_size_category": "Medium (50-99)",
"park_count": 614
},
{
"park_size_category": "Large (100-249)",
"park_count": 423
},
{
"park_size_category": "Very Large (250+)",
"park_count": 98
}
]
}
Privacy gating: Counties and metros with fewer than
3 rent data points will have their rent stats suppressed (only
count will be returned) to prevent re-identification
of individual submitters.
Parks GeoJSON
Returns all approved parks that have coordinates, optimized for map rendering. This is a lightweight endpoint designed for plotting markers on a map.
curl "https://fairlot.org/api/v1/parks-geo" \
-H "Authorization: Bearer fl_live_your_key_here"{
"parks": [
{
"id": "vt-chittenden-birchwood",
"name": "Birchwood Mobile Home Park",
"latitude": 44.4918,
"longitude": -73.1148,
"lot_count": 84,
"county": "Chittenden",
"state": "VT",
"owner_name": "Green Mountain Properties LLC",
"latest_lot_rent": 435.0
}
// ... more parks
]
}
Field gating: Unauthenticated users will see
owner_name as null.
The latest_lot_rent field is visible without auth only
for a limited number of parks per page as a teaser.
CSV Export
Export park data as a CSV file. Requires Founding Member plan. The CSV includes watermark rows containing the authenticated user's email to prevent unauthorized redistribution.
Accepts the same filter parameters as the
List Parks endpoint (state,
county, has_rent, etc.).
curl "https://fairlot.org/api/v1/export/parks?state=VT&has_rent=true" \
-H "Authorization: Bearer fl_live_your_key_here" \
-o parks.csvimport requests
resp = requests.get(
"https://fairlot.org/api/v1/export/parks",
headers={"Authorization": "Bearer fl_live_your_key_here"},
params={"state": "VT", "has_rent": "true"}
)
with open("parks.csv", "wb") as f:
f.write(resp.content)
print("Saved", len(resp.content), "bytes")const resp = await fetch(
"https://fairlot.org/api/v1/export/parks?state=VT&has_rent=true",
{ headers: { "Authorization": "Bearer fl_live_your_key_here" } }
);
const blob = await resp.blob();
// Save or process the CSV blobReturns a text/csv response with columns including Park ID,
Name, County, Address, City, State, Zip, Lot Count, Owner, Phone,
Metro Area, Size Category, Lot Rent (Monthly), Rent Source,
Rent Collected At, Latitude, and Longitude.
List States
Returns a list of all states in the database with park counts and the number of parks that have rent data. This endpoint is public and does not require authentication.
curl "https://fairlot.org/api/v1/states"[
{
"state": "FL",
"park_count": 1811,
"parks_with_rent": 18
},
{
"state": "CO",
"park_count": 762,
"parks_with_rent": 0
},
{
"state": "NV",
"park_count": 375,
"parks_with_rent": 288
},
{
"state": "VT",
"park_count": 238,
"parks_with_rent": 216
}
]Response Schemas
ParkListItemResponse
Each park in the /api/v1/parks response contains these fields:
| Field | Type | Description |
|---|---|---|
| id | string | Unique park identifier |
| name | string | Park name |
| county | string? | County name |
| city | string? | City name |
| address | string? | Street address (gated) |
| state | string? | Two-letter state code |
| zip | string? | ZIP code (gated) |
| lot_count | integer? | Number of lots in the park |
| owner_name | string? | Park owner name (gated) |
| status | string? | Registration status (e.g., "Approved") |
| phone | string? | Park phone number (gated) |
| metro_area | string? | Metro/MSA area name |
| park_size_category | string? | Size bucket (gated) |
| source | string? | Data source identifier (gated) |
| fetched_at | string? | ISO 8601 timestamp of last data pull (gated) |
| latest_lot_rent | float? | Most recent monthly lot rent (gated) |
| latest_rent_source | string? | Source of the rent data (gated) |
| latest_rent_collected_at | string? | When rent was collected (gated) |
| latitude | float? | GPS latitude |
| longitude | float? | GPS longitude |
| age_restriction | string? | Age restriction type (e.g., "55+") |
| estimated_occupancy | float? | Estimated occupancy rate (0-1) |
LotRentResponse
Each entry in the lot_rents array on park detail:
| Field | Type | Description |
|---|---|---|
| lot_rent_monthly | float | Monthly lot rent amount |
| lot_rent_min | float? | Minimum lot rent in the park |
| lot_rent_max | float? | Maximum lot rent in the park |
| lot_rent_double_wide | float? | Lot rent for double-wide homes |
| source | string? | Data source identifier |
| confidence | string? | Confidence level: "high", "medium", or "low" |
| collected_at | string? | ISO 8601 timestamp of data collection |
| notes | string? | Additional notes about this data point |
RentStatsResponse
Aggregate rent stats returned within the /api/v1/stats response:
| Field | Type | Description |
|---|---|---|
| count | integer | Number of rent data points in this group |
| median | float? | Median monthly lot rent |
| avg | float? | Average monthly lot rent |
| min | float? | Lowest lot rent in the group |
| max | float? | Highest lot rent in the group |
Field Gating
The following fields are set to null for unauthenticated
(free tier) users on the /api/v1/parks endpoint:
phoneowner_nameaddresszipsourcefetched_atpark_size_categorylatest_lot_rentlatest_rent_sourcelatest_rent_collected_at
Exception: A limited number of parks per page show rent
fields (latest_lot_rent, latest_rent_source,
latest_rent_collected_at) as a teaser for unauthenticated users.
Support
For API questions, integration help, or to request a dedicated API key, contact us at [email protected].
If you need higher rate limits or custom data exports for enterprise use, let us know your requirements and we will work with you on a solution.