The most reliable Visor workflow is facet first, listing second.
- Use
/v1/facets to discover the values that exist in inventory.
- Use
/v1/listings to fetch matching vehicle rows.
- Use
/v1/vins/{vin}, /v1/listings/{listing_id}, and /v1/dealers/{dealer_id} when you already know the identifier.
This matters because vehicle data has real-world naming differences. A user may type f150, but the canonical model value in inventory may be F-150.
Discover before filtering
Start broad:
curl "https://api.visor.vin/v1/facets?facets=make&facet_value_limit=100" \
-H "Authorization: Bearer $VISOR_API_KEY"
Then use the exact returned make to discover models:
curl "https://api.visor.vin/v1/facets?facets=model&make=Ford&facet_value_limit=100" \
-H "Authorization: Bearer $VISOR_API_KEY"
Then query listings:
curl "https://api.visor.vin/v1/listings?make=Ford&model=F-150&state=TX&limit=10" \
-H "Authorization: Bearer $VISOR_API_KEY"
Facet response shape
Facet totals are returned at data.total.
Categorical buckets are keyed by facet name under data.facets:
{
"data": {
"total": 1234,
"facets": {
"model": [{ "value": "F-150", "count": 456 }]
}
}
}
Numeric range buckets are under data.range_facets, and numeric stats are under data.stats.
Filter syntax
Most filters are query parameters:
make=Toyota&model=Camry&state=CA&limit=10
Comma-separated filters match any of the values:
make=Toyota,Honda&state=CA,TX
Ranges use min_ and max_ fields:
min_price=20000&max_price=35000&min_year=2021
Some fields are closed vocabularies and reject unsupported values instead of returning a silent empty result. Examples include inventory_type, keywords, and dealer_type.
Open categorical values such as trim, version, features, options_packages, assembly_country, and color values should be discovered with /v1/facets before filtering.
fields controls response projection. It does not filter rows. For example, use features=sunroof to filter and fields=default,features to include the feature list in each returned row.
Geography
Use state filters for broad searches:
Use a ZIP-code radius for local searches:
postal_code=98101&radius=100&sort=distance
Use latitude and longitude when you already have coordinates:
latitude=47.6062&longitude=-122.3321&radius=100&sort=distance
Use bbox for map viewport searches.
Inventory status
Active inventory is the default:
Use sold inventory when you need market history:
inventory_status=sold&sold_within_days=30
Sold inventory starts only after a listing has been missing from the dealer’s inventory feed for at least three days and passed sold-quality checks. If it has been missing for less than three days, it is missing, not sold.
Use snapshot_date=YYYY-MM-DD for historical active-inventory snapshots. snapshot_date cannot be combined with sold inventory filters.
VIN patterns
Use vin_pattern to match one or more positions in a 17-character US VIN:
? matches exactly one VIN position. * may appear only at the end. Short masks are treated as prefixes, so vin_pattern=1HG is equivalent to 1HG*.
Dealer attribution
Public inventory is deduplicated by VIN and assigned to the dealer Visor believes owns the listing. Dealer-scoped inventory counts can differ from raw dealer feed counts when the same VIN appears in multiple feeds.
Use /v1/dealers/{dealer_id}/listings for one dealer. Use /v1/listings?dealer_id=id1,id2 for an explicit multi-dealer listing search.
When a search returns no rows
- Remove the narrowest filter and retry.
- Run
/v1/facets with the remaining filters to inspect available values.
- Check spelling and punctuation for make, model, trim, options, and features.
- Check whether you meant active inventory, sold inventory, or a historical snapshot.
- Check whether a geographic filter is too tight.
Successful zero-result searches are billable, so start with facets when you are unsure.