Each response has a market summary, the comparable listings, and notes on coverage.
Price by trim
For every trim: price, average and median mileage, and average days on market.
Price trends
The 30, 60 and 90-day price change for each trim.
Market size
How many cars were listed, how many are still active, and how many left the market in your time window.
Comparable listings
Each car with VIN, price and price history, miles, colors, dealer, city and state, distance, first and last seen dates, days on market, listing URL and photo.
You can narrow the pool by trim, fuel type, mileage range and look-back window. You can sort listings by distance, price, mileage or days on market.
Who uses market comps data
Market comps answer one question: what are similar cars listed for near this ZIP right now?
Lenders
Check a vehicle's collateral value against comparable listings near the borrower, with price, mileage and trim side by side.
Insurers
Pull actual cash value comparables for the same year, make, model and trim near the loss location, each with its listing URL.
Marketplaces
Show buyers the local market next to a listing: price for the trim, typical days on market and the recent price trend.
Need the free version for a quick price check? See the
free AI data API
on the API overview page.
API reference
One call answers the question: for a given Year / Make / Model in a market
area, what is listed and what has left the market, at what prices, and how does it
break down by trim. The response has two layers — a
per-trim market summary
and the
individual comparable listings
behind it.
Vehicle to analyze (e.g. 2022 / Toyota / RAV4). Year from 1990 through the next model year. Make and model are matched case-insensitively.
zip
required
5-digit US ZIP code — center of the market area.
radius
required
Radius in miles, 10–500. Coverage is computed on precomputed rings of
50 / 100 / 200 / 500 miles: the requested radius snaps
up
to the nearest ring, and the ring actually used is echoed back as
query.radius_miles_effective
.
trim
optional
Restrict the response to a single trim. Matched case-insensitively
against the canonical trim labels returned in
summary.by_trim
.
fuel_type
optional
Powertrain filter:
gas
,
hybrid
(includes plug-in hybrids),
electric
or
all
(default). Classified from the VIN build prefix via factory decode
data, so "RAV4" and "RAV4 Hybrid" listings mixed in source feeds
separate cleanly. Applies to the whole response; vehicles whose
build cannot be decoded are excluded while the filter is active —
if decode data is temporarily unavailable, a fuel_type filter can
return an empty pool (check
meta.fuel_types_present
).
odometer_from odometer_to
optional
Mileage range filter. Either bound works on its own:
odometer_to=60000
means "60,000 miles or less",
odometer_from=10000
means "10,000 miles or more". Applies to the
whole response
(summary and listings), except the pool-level
trend_*
fields. Vehicles with unknown mileage are excluded
while the filter is active.
odometer_from=0
is treated as "no bound";
odometer_to
must be at least 1.
days
optional
Look-back window in days — any value from
1
to
150
(default 90). A vehicle is in the window if it had at least one
market observation within the last N days. Mutually exclusive with
months
.
Note:
summary-level DOM figures are measured
within
this window; listing rows report full-history
first_seen
and DOM (see the listings reference).
months
optional
Convenience alias for the look-back window in months back from
today:
1
to
5
(= 30–150 days). Example:
months=3
covers the last 90 days. Mutually exclusive with
days
.
status
optional
active
,
sold
(removed from market) or
all
(default). Filters the
listings
layer only — the
summary
always covers both, so
listed = active + sold
stays true. (This differs from
fuel_type
,
trim
and odometer, which narrow the summary too.)
limit, offset
optional
Page size (default 50, max 500) and pagination offset.
meta.total_listings
carries the full match count, so pages =
ceil(total_listings / limit)
.
sort
optional
distance
(default),
price
,
mileage
or
days_on_market
— all ascending. Sorting is applied to the full match set before
pagination, so page boundaries are stable.
Response structure
Four top-level blocks:
query
(echo of what was asked, with effective values),
summary
(the market answer),
listings
(the comparables behind it) and
meta
(coverage and pagination info).
Echo of the request after normalization — store it alongside results so you always know what a cached response actually covers.
Field
Type
Meaning
year / make / model
int / string
The vehicle spec the response covers.
zip
string
Center ZIP of the market area.
radius_miles
int
The radius you requested.
radius_miles_effective
int
The precomputed ring actually used (50 / 100 / 200 / 500). Always ≥ the requested radius.
days
int
The effective look-back window in days, 1–150
(
months
× 30 when
months
was passed).
months
int
nullable
The
months
alias as passed, or null when the window was set via
days
.
status
string
The status filter applied to the listings layer.
trim
string
nullable
The trim filter, or null when all trims were requested.
fuel_type
string
The powertrain filter applied (gas / hybrid / electric / all).
odometer_from / odometer_to
int
nullable
The mileage bounds applied, or null when that bound was not set.
sort / limit / offset
string / int / int
The sort key and pagination actually applied.
The `summary` block
The "what is this car worth here, right now" layer. Counts cover the
whole match set regardless of the
status
parameter, so the identity
listed = active + sold
always holds.
Field
Type
Meaning
listed
int
Unique vehicles (VINs) seen on the market in the window, after quality filters. One vehicle listed on four marketplaces counts once.
active
int
Of those, how many are still in active rotation right now (observed within the last 14 days — see the status field).
sold
int
How many disappeared from active rotation during the window
(including "active"-flagged rows not observed for 14+ days) —
removed from market
. A strong proxy for a sale, but not a title-verified transaction.
avg_days_on_market
int
nullable
Average days from a vehicle's first observed appearance
within the look-back window
to its last day in rotation (or today, if still active) — so it is
capped by the
days
parameter. Null when the pool is empty.
by_trim
array
One row per trim, ordered by listing volume (largest first). Fields below.
Each `by_trim` row
Field
Type
Meaning
trim
string
Canonical trim label, resolved from VIN and equipment data against
the model's factory trim vocabulary — not from free-text dealer
titles. Listings whose trim cannot be confidently resolved are
grouped under
"Other"
.
listed / sold
int
Vehicle counts for this trim, same semantics as the summary-level fields.
price.min / max
int (USD)
Lowest and highest asking price in the trim's pool, after junk-price filtering (see "How the numbers are built").
price.p25 / median / p75
int (USD)
25th / 50th / 75th percentile of asking prices
(linearly interpolated). The p25–p75 band is the "typical retail
range"; price a vehicle against the median.
price.avg
int (USD)
Arithmetic mean. More outlier-sensitive than the median — prefer the median for pricing decisions.
avg_miles / median_miles
int
nullable
Average / median odometer of vehicles in this trim that report mileage. Null when none do.
avg_dom
int
Average days on market for this trim — how fast this trim turns in
this area. Measured within the look-back window (see the
days
parameter).
trend_30d_pct / trend_60d_pct / trend_90d_pct
float
nullable
Percent change of the weekly weighted-average asking price over the
last 30 / 60 / 90 days.
Pool-level:
computed over the whole Year/Make/Model pool in the area, so the
same values appear on every trim row. Trend windows are fixed at
30/60/90 days regardless of the
daysmonths
parameter. Computed as the median of the first two vs last two
full weeks in the window (single-week anchors when only 3 usable
weeks); the still-accumulating current week is dropped, weeks
with fewer than 5 listings are ignored, and fewer than 3 usable
weeks yields null. Negative = prices softening.
Null when there are not enough weekly data points or when trend
data is temporarily unavailable.
Each `listings` row
One row per unique vehicle (VIN). When the same car is listed on several
marketplaces, the rows are collapsed into one with the most recent state;
price_history
is the dominant source's cleaned series (see the field reference).
Field
Type
Meaning
vin
string
17-character VIN — the stable identifier to join on.
trim
string
Canonical trim (same vocabulary as
by_trim.trim
), so listings roll up cleanly into the summary.
price
int (USD)
Most recent asking price observed.
price_history
int[]
Chronological asking prices across the listing's lifetime from its
dominant source
(the marketplace with the most observations — mixing sources
produced fake daily "sawtooth" swings), one point per day,
consecutive duplicates and mid-series bounce-backs to the
previous price collapsed (the final point always survives so the
tail matches the current price), obvious glitches outside
0.4–2.5× of the current price dropped (the band is skipped when
the current price is itself below $1,500, or when it would
reject every point). First element = earliest price; comparing
first vs last shows the total markdown.
miles
int
nullable
Odometer reading as advertised. Null when the source did not report it.
fuel_type
string
nullable
gas
,
hybrid
(incl. plug-in) or
electric
— classified from the VIN build prefix via factory decode data.
Null when the build could not be decoded.
condition
string
nullable
new
(under 500 miles — dealer stock/demo) or
used
. Null when mileage is unknown.
observations
int
Distinct days this VIN was observed within the look-back window — a confidence signal (a 1-observation "sold" is weaker evidence than a 15-observation one).
exterior_color / interior_color
string
nullable
Colors as advertised by the seller (free-text, not normalized — expect "Gray" and "Magnetic gray metallic" alike).
dealer
string
nullable
Selling dealer's name as advertised. Null for rows where the seller could not be identified.
city / state
string
nullable
Seller's location. State is always normalized to a 2-letter USPS code ("Indiana" → "IN"); null when the feed value cannot be mapped.
distance_miles
float
nullable
Miles from the requested ZIP. With
sort=distance
(default) computed from ZIP-code centroids so ordering is stable
across pages; with other sort keys, exact listing coordinates are
used when available and sanity-checked against the ZIP centroid
(a divergence over 25 miles means feed garbage and falls back to
the centroid).
first_seen / last_seen
date (YYYY-MM-DD)
First and most recent day this VIN was observed. Listing rows use
the VIN's
full price-history span
when available, so first_seen can pre-date the look-back window;
summary-level DOM figures remain window-scoped.
status
"active" | "sold"
active
= currently in rotation AND observed within the last 14 days
(older "active" flags are stale feed artifacts and are reported
as sold);
sold
= removed from market (see the summary note — a proxy, not a verified sale).
days_on_market
int
Days from
first_seen
to the last day in rotation (or today, if active). Uses the VIN's
full history span, so it CAN exceed the
days
window — only summary-level DOM figures are window-scoped.
days_on_market_in_window
int
The same measure restricted to the look-back window (never exceeds
days
).
sort=days_on_market
orders by THIS value, so cross-page ordering stays stable even
when full-history DOM differs.
url
string
nullable
Link to the source listing (marketplace VDP or dealer site), always an absolute http(s) URL. Null when the source page cannot be reconstructed, when the value is not a valid absolute URL, or for marketplaces without a working public deep-link (currently iSeeCars). Listings do go offline after a sale — expect some links to 404 for sold vehicles.
photo
string
nullable
Primary photo. Served from our image CDN (stable after the source goes down, sized to fit 800×600) when we host it; otherwise the source's own URL (https-upgraded), which can go offline with the listing.
The `meta` block
Field
Type
Meaning
total_listings
int
Total rows matching the query (after the
status
filter) across all pages — use with
limitoffset
for pagination.
truncated
bool
True if the match set hit the internal safety cap and the summary may undercount. Practically only possible for nationwide-scale queries.
zip_count
int
Number of ZIP codes inside the effective radius.
prefix8_count
int
Number of distinct VIN build-prefixes matched for this Year/Make/Model — a coverage indicator.
ignored_params
string[]
Present only when the request contained query parameters the API
does not understand (e.g. a leftover
price_max
from another provider) — they were ignored, and this field is the
warning.
fuel_types_present
object
Powertrain mix of the client's slice: counted AFTER the
trim
and odometer filters but BEFORE the
fuel_type
filter itself (its point is to show what that filter hides), e.g.
{ "gas": 66, "hybrid": 105 }
— so a mixed gas/hybrid market is never silently averaged without
you knowing.
sources
string[]
Internal dataset identifiers the response was assembled from (for support/debugging).
How the numbers are built
One vehicle = one row.
The same car scraped from several marketplaces is deduplicated by VIN;
counts are counts of cars, not of ads.
Junk prices are filtered.
Asking prices below $1,500 are always excluded; when the pool has at
least 5 priced vehicles, prices far below the pool median
(down-payment placeholders) are excluded too. The same $1,500 floor
applies to
price_history
points. Filtered rows appear in neither the statistics nor the listings.
"Sold" means removed from market.
We track each VIN across marketplaces daily; when it leaves active
rotation — or hasn't been observed for 14+ days — we count it as
sold. It is a strong proxy, not a title-verified sale. The
observations
field tells you how many distinct days back the evidence goes.
Powertrains are separated.
Source feeds mix "RAV4" and "RAV4 Hybrid" under one model name;
every VIN is classified from factory decode data and reported in
fuel_type
, with the pool's mix in
meta.fuel_types_present
— filter with the
fuel_type
parameter to price against the right population.
Trims are VIN-resolved.
Trim labels come from VIN and equipment data matched against the
model's factory trim vocabulary, so "SE CVT" and "SE" land in the same
bucket and junk titles land in
Other
.
Freshness.
The underlying listing archive ingests hundreds of thousands of new
listings and millions of updates daily; the comps dataset the endpoint
reads from refreshes several times a day.
Discovering valid makes, models and trims
GET /api/v1/market/options
(same Bearer auth) returns the vocabulary the comps endpoint
understands — call it without parameters for the list of makes, with
?make=Toyota
for that make's models, and with
?make=Toyota&model=RAV4
for the canonical trim labels usable in the
trim
filter. Model spelling is forgiving on the comps endpoint itself —
"RAV-4" and "Rav 4" resolve to RAV4 — but exact canonical labels are
required for
trim
.