1
Use GET /listings/metrics/all to pull monthly performance data for a specific listing. Set num_months up to 60 to retrieve 5 years of history. Each month includes occupancy, average daily rate (ADR), RevPAR, revenue, and minimum nights.
Python
import requests
API_KEY = "your_api_key_here"
BASE_URL = "https://api.airroi.com/v1"
# Pull up to 60 months of history for a specific listing
listing_id = "abc123"
response = requests.get(
f"{BASE_URL}/listings/metrics/all",
headers={"X-API-KEY": API_KEY},
params={
"id": listing_id,
"num_months": 60,
"currency": "usd"
}
)
data = response.json()
print(f"Retrieved {len(data)} months of data")
print(f"Date range: {data[0]['date']} to {data[-1]['date']}")
# Display recent months
print("\nRecent performance:")
for month in data[-6:]:
print(f" {month['date']}: "
f"Occ {month['occupancy']:.1%}, "
f"ADR {month['average_daily_rate']:,.0f}, "
f"Rev {month['revenue']:,.0f}")2
Use POST /markets/metrics/all to pull aggregate market data with percentile distributions. Each month returns avg, p25, p50, p75, and p90 values for occupancy, ADR, RevPAR, and revenue, plus the total active listings count. This lets you see the full spectrum of performance in a market.
Python
# Pull market-level history with percentile distributions
response = requests.post(
f"{BASE_URL}/markets/metrics/all",
headers={"X-API-KEY": API_KEY},
json={
"market": {
"country": "united_states",
"region": "tennessee",
"locality": "nashville"
},
"num_months": 60,
"currency": "usd"
}
)
data = response.json()
print(f"Market history: {len(data)} months")
# Show percentile distributions for a recent month
latest = data[-1]
print(f"\n{latest['date']} Market Snapshot:")
print(f" Occupancy: avg={latest['occupancy']['avg']:.1%}, "
f"p25={latest['occupancy']['p25']:.1%}, "
f"p75={latest['occupancy']['p75']:.1%}")
print(f" ADR: avg={latest['average_daily_rate']['avg']:,.0f}, "
f"p25={latest['average_daily_rate']['p25']:,.0f}, "
f"p75={latest['average_daily_rate']['p75']:,.0f}")
print(f" Revenue: avg={latest['revenue']['avg']:,.0f}, "
f"p25={latest['revenue']['p25']:,.0f}, "
f"p75={latest['revenue']['p75']:,.0f}")
print(f" Active listings: {latest['active_listings_count']}")3
Calculate month-over-month and year-over-year growth rates to understand market trajectory. Smooth out noise with rolling averages. Compute the Compound Annual Growth Rate (CAGR) for a single number that summarizes long-term growth.
Python
# Trend analysis: MoM growth, YoY growth, rolling averages, and CAGR
# Month-over-month growth rates
for i in range(1, len(data)):
prev_rev = data[i-1]["revenue"]["avg"]
curr_rev = data[i]["revenue"]["avg"]
if prev_rev > 0:
mom_growth = (curr_rev - prev_rev) / prev_rev * 100
data[i]["mom_growth"] = mom_growth
# Year-over-year growth rates (compare same month, 12 periods apart)
for i in range(12, len(data)):
prev_rev = data[i-12]["revenue"]["avg"]
curr_rev = data[i]["revenue"]["avg"]
if prev_rev > 0:
yoy_growth = (curr_rev - prev_rev) / prev_rev * 100
data[i]["yoy_growth"] = yoy_growth
# 3-month rolling average for smoothing
for i in range(2, len(data)):
avg_3mo = sum(
data[j]["revenue"]["avg"] for j in range(i-2, i+1)
) / 3
data[i]["rolling_avg_3mo"] = avg_3mo
# CAGR (Compound Annual Growth Rate)
first_year_rev = sum(d["revenue"]["avg"] for d in data[:12]) / 12
last_year_rev = sum(d["revenue"]["avg"] for d in data[-12:]) / 12
years = len(data) / 12
cagr = ((last_year_rev / first_year_rev) ** (1 / years) - 1) * 100
print(f"Revenue CAGR over {years:.1f} years: {cagr:.1f}%")
print(f"\nRecent YoY growth rates:")
for m in data[-6:]:
yoy = m.get("yoy_growth", "N/A")
yoy_str = f"{yoy:+.1f}%" if isinstance(yoy, float) else yoy
print(f" {m['date']}: {yoy_str}")4
Group data by calendar month and compare the same month across years. This eliminates seasonality and reveals true growth or decline. Classify each month as growing (greater than 5% increase), declining (greater than 5% decrease), or stable.
Python
# Year-over-year comparison: group by calendar month
from collections import defaultdict
# Group data by month number
monthly_groups = defaultdict(list)
for m in data:
year, month = m["date"].split("-")
monthly_groups[int(month)].append({
"year": int(year),
"occupancy": m["occupancy"]["avg"],
"adr": m["average_daily_rate"]["avg"],
"revenue": m["revenue"]["avg"],
})
month_names = [
"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
]
# Compare each month across years
print("Revenue by Month (Year-over-Year):")
print(f"{'Month':<6}", end="")
years_available = sorted(set(
int(m["date"].split("-")[0]) for m in data
))
for y in years_available:
print(f"{y:>10}", end="")
print(f"{'Trend':>10}")
for month_num in range(1, 13):
entries = monthly_groups.get(month_num, [])
print(f"{month_names[month_num]:<6}", end="")
for y in years_available:
match = next((e for e in entries if e["year"] == y), None)
if match:
print(f"{match['revenue']:>8,.0f}", end="")
else:
print(f"{'---':>10}", end="")
# Trend indicator
if len(entries) >= 2:
first = entries[0]["revenue"]
last = entries[-1]["revenue"]
trend = "Growing" if last > first * 1.05 else "Declining" if last < first * 0.95 else "Stable"
print(f"{trend:>10}")
else:
print()5
Classify a market by comparing supply growth (active_listings_count trend) against revenue growth. Growing supply with growing revenue indicates a healthy market. Growing supply with flat revenue signals oversaturation. This framework helps you decide whether a market is worth entering.
Python
# Market maturity assessment using supply and revenue trends
# Get the first and last 12-month periods
first_12 = data[:12]
last_12 = data[-12:]
# Calculate supply growth
avg_supply_first = sum(d["active_listings_count"] for d in first_12) / 12
avg_supply_last = sum(d["active_listings_count"] for d in last_12) / 12
supply_growth = ((avg_supply_last / avg_supply_first) - 1) * 100
# Calculate revenue growth
avg_rev_first = sum(d["revenue"]["avg"] for d in first_12) / 12
avg_rev_last = sum(d["revenue"]["avg"] for d in last_12) / 12
revenue_growth = ((avg_rev_last / avg_rev_first) - 1) * 100
# Classify market maturity
if supply_growth > 10 and revenue_growth > 10:
classification = "Healthy Growth"
description = "Both supply and revenue are growing. Market has room for new entrants."
elif supply_growth > 10 and revenue_growth <= 5:
classification = "Oversaturating"
description = "Supply growing faster than revenue. Increased competition diluting returns."
elif supply_growth <= 5 and revenue_growth > 10:
classification = "Supply Constrained"
description = "Revenue growing with flat supply. Opportunity for new listings."
elif supply_growth < 0 and revenue_growth < 0:
classification = "Declining"
description = "Both supply and revenue shrinking. Market fundamentals weakening."
else:
classification = "Mature / Stable"
description = "Balanced growth. Established market with predictable returns."
print("=== Market Maturity Assessment ===")
print(f"Supply growth: {supply_growth:+.1f}% ({avg_supply_first:.0f} -> {avg_supply_last:.0f} listings)")
print(f"Revenue growth: {revenue_growth:+.1f}% ({avg_rev_first:,.0f} -> {avg_rev_last:,.0f}/mo avg)")
print(f"\nClassification: {classification}")
print(f"Assessment: {description}")6
Format the historical data as CSV for import into Excel or Tableau, or as JSON for web applications. In Python, use pandas to create a DataFrame for further analysis, then export with a single line of code.
Python
import pandas as pd
import json
# Create a pandas DataFrame from market history
df = pd.DataFrame([
{
"date": m["date"],
"occupancy_avg": m["occupancy"]["avg"],
"occupancy_p25": m["occupancy"]["p25"],
"occupancy_p75": m["occupancy"]["p75"],
"adr_avg": m["average_daily_rate"]["avg"],
"adr_p25": m["average_daily_rate"]["p25"],
"adr_p75": m["average_daily_rate"]["p75"],
"revenue_avg": m["revenue"]["avg"],
"revenue_p25": m["revenue"]["p25"],
"revenue_p75": m["revenue"]["p75"],
"revpar_avg": m["rev_par"]["avg"],
"active_listings": m["active_listings_count"],
}
for m in data
])
# Set date as index
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date")
print(f"DataFrame shape: {df.shape}")
print(f"\nColumns: {list(df.columns)}")
print(f"\nSample data:")
print(df.tail())
# Export to CSV for Excel or Tableau
df.to_csv("nashville_str_history.csv")
print("\nExported to nashville_str_history.csv")
# Export to JSON for web applications
df.reset_index().to_json(
"nashville_str_history.json",
orient="records",
date_format="iso"
)
print("Exported to nashville_str_history.json")Keep exploring the AirROI API with these related tutorials.
The API provides up to 60 months (5 years) of monthly historical data via the num_months parameter. The actual availability depends on how long a listing or market has been tracked. Most major markets have 5+ years of data.
Listing-level history includes occupancy, average_daily_rate, rev_par, revenue, and min_nights for each month. Market-level history adds percentile distributions (p25, p50, p75, p90) for all metrics plus active_listings_count to track supply trends.
The historical metrics endpoints return monthly aggregated data, which is optimal for trend analysis and reduces data volume. For more granular data, you can use listing-level future rates endpoints which provide daily pricing data for upcoming dates.
Group your data by calendar month (e.g., all January values), then compare the same month across years. The formula is: (Current Year Value - Prior Year Value) / Prior Year Value * 100. This eliminates seasonality from the comparison.
Listing-level history (GET /listings/metrics/all) returns exact performance for a single property. Market-level history (POST /markets/metrics/all) returns aggregate statistics with percentile distributions across all listings in a market, giving you the full range of performance.
Yes. The API returns JSON which can easily be converted to CSV or loaded into a pandas DataFrame. Step 6 of this tutorial shows exactly how to create a DataFrame and export to CSV for use in Excel, Tableau, or other analysis tools.
Stay ahead of the curve
Join our newsletter for exclusive insights and updates. No spam ever.