AirDNA APIairdna.co ↗
Access AirDNA market performance data via API: ADR, occupancy, RevPAR, annual revenue, active listings, and market scores for STR markets worldwide.
What is the AirDNA API?
The AirDNA API gives developers access to short-term rental market performance data across two endpoints, covering metrics like average daily rate, occupancy, RevPAR, annual revenue, and AirDNA Market Score. Use search_markets to find market and submarket IDs by name, then pass those location slugs to get_market_overview to retrieve trailing-twelve-month performance figures with year-over-year changes for any supported city or region.
curl -X GET 'https://api.parse.bot/scraper/19809723-51f8-4a93-854b-914921c64414/search_markets?query=Denver&limit=5' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace airdna-co-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: AirDNA SDK — search markets, then fetch full overview."""
from parse_apis.airdna_co_api import AirDNA, MarketNotFound
client = AirDNA()
# Search for markets matching a query; limit= caps total items fetched.
for market in client.markets.search(query="Miami", limit=5):
print(market.market_name, market.state_name, market.region_level)
# Drill down: take the first result and fetch its full market overview.
hit = client.markets.search(query="Denver", limit=1).first()
if hit is not None:
# Use the search result's location fields to get the overview.
overview = client.market_overviews.get(
city=hit.market_name.lower().replace(" ", "-"),
state=hit.state_name.lower().replace(" ", "-"),
country=hit.country_code,
)
print(overview.market.title)
print("Overall score:", overview.market_score.overall)
print("Rental demand:", overview.market_score.subscores.rental_demand)
print("Occupancy:", overview.metrics.occupancy.value, overview.metrics.occupancy.yoy_change)
print("ADR:", overview.metrics.average_daily_rate.value)
print("Revenue:", overview.metrics.annual_revenue.value)
print("Last updated:", overview.last_updated)
# Point lookup with error handling for a non-existent market.
try:
client.market_overviews.get(city="nonexistentcity", state="colorado", country="us")
except MarketNotFound:
print("Market not found — expected for invalid city slug")
print("exercised: markets.search / market_overviews.get / MarketNotFound")
Search for short-term rental markets and submarkets by name. Returns market IDs, location hierarchy, and region level (market or submarket). Use the returned country_code, state_name, and market_name to construct inputs for get_market_overview.
| Param | Type | Description |
|---|---|---|
| limit | integer | Maximum number of results to return (1-50). |
| queryrequired | string | Search query for a city, market, or neighborhood name (e.g. 'Denver', 'Miami Beach'). |
{
"type": "object",
"fields": {
"total": "integer count of results returned",
"markets": "array of market objects with country_code, market_id, submarket_id, market_name, submarket_name, state_name, country_name, region_level, and relevance score"
},
"sample": {
"data": {
"total": 2,
"markets": [
{
"score": 1463.72,
"market_id": "airdna-163",
"state_name": "Colorado",
"market_name": "Denver",
"country_code": "us",
"country_name": "United States",
"region_level": "market",
"submarket_id": null,
"submarket_name": null
},
{
"score": 879.06,
"market_id": "airdna-163",
"state_name": "Colorado",
"market_name": "Denver",
"country_code": "us",
"country_name": "United States",
"region_level": "submarket",
"submarket_id": "airdna-1490",
"submarket_name": "Downtown Denver"
}
]
},
"status": "success"
}
}About the AirDNA API
Endpoints and What They Return
The search_markets endpoint accepts a freeform query string (e.g. 'Denver', 'Miami Beach') and returns up to 50 matching market and submarket objects. Each result includes a market_id, submarket_id, market_name, submarket_name, state_name, country_code, country_name, and a region_ type flag indicating whether the result is a market or submarket. This is the entry point for resolving human-readable place names into the location slugs required by the overview endpoint.
Market Overview Data
get_market_overview takes three slug parameters — city, state, and country — and returns a structured performance snapshot for that STR market. The metrics object contains five keys: active_listings, annual_revenue, occupancy, average_daily_rate, and revpar. Each metric carries a value and a yoy_change field, enabling direct period-over-period comparison without any additional computation. The market_score object returns an integer score from 40 to 100 alongside five subscores: rental_demand, seasonality, revenue_growth, investability, and regulation.
Coverage and Freshness
All performance data covers the trailing twelve months, with the exact date range surfaced in the temporal_coverage field. The last_updated field returns an ISO date string (YYYY-MM-DD) indicating when AirDNA last refreshed the figures. Location inputs must be formatted as lowercase hyphenated slugs (e.g. miami-beach, new-york), which can be derived directly from the market_name and state_name values returned by search_markets.
The AirDNA API is a managed, monitored endpoint for airdna.co — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when airdna.co changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official airdna.co API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Screen STR investment markets by comparing
annual_revenueandoccupancyvalues across multiple cities. - Track year-over-year ADR trends in a target market using the
yoy_changefield onaverage_daily_rate. - Rank markets by
market_scoreoverall or by individual subscores likeinvestabilityorregulation. - Build a market-selection tool that lets users search by city name and retrieve live performance benchmarks.
- Alert users when occupancy or RevPAR shifts significantly by polling
get_market_overviewperiodically and comparing against stored values. - Evaluate seasonality risk in a market using the
seasonalitysubscore before committing to a property acquisition.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does AirDNA have an official developer API?+
What does `search_markets` return beyond a market name?+
markets array includes a market_id, submarket_id, market_name, submarket_name, state_name, country_code, country_name, and a region type flag. The region flag distinguishes top-level markets from submarkets (e.g. a neighborhood within a city). You use market_name and state_name to construct the slug inputs for get_market_overview.Does the API return property-level or listing-level data?+
active_listings gives you a count of listings in the market, but individual property addresses, listing URLs, nightly prices, or host data are not exposed. You can fork this API on Parse and revise it to add a property-level endpoint if that data is accessible from AirDNA's public pages.How current is the data returned by `get_market_overview`?+
last_updated field in the response carries an ISO date string showing when AirDNA last refreshed the market figures. All metrics reflect the trailing twelve months, and the exact date range is in the temporal_coverage field. Refresh cadence is controlled by AirDNA's own publication schedule, not by how frequently you call the API.