/v1 endpoints require an API key:
?api_key=... are rejected.
MCP server for agents
Prefer to let an AI agent query Visor for you? The hosted MCP server lets Claude, ChatGPT, Codex, and other agents call the Public API in plain language — no HTTP requests to write:Authorization: Bearer <VISOR_API_KEY> instead.
See Connect to your AI agent for step-by-step setup for Claude, ChatGPT, Claude Code, Codex, OpenCode, and the OpenAI and Claude APIs, plus how the search and execute tools work.
Listings
/v1/listings with limit and offset for pagination. The deprecated /v1/listings/search compatibility path still accepts per_page and one-based page, maps them to limit and offset, and returns deprecation headers. Migrate old requests such as /v1/listings/search?per_page=100&page=2 to /v1/listings?limit=100&offset=100.
Useful filters include vehicle fields (make, model, trim, year, body_type, transmission, drivetrain, fuel_type, powertrain_type, engine, colors, seating_capacity, cylinders, doors), dealer/inventory fields (dealer_id, state, dealer_type, availability_status, inventory_type), option and keyword fields (options_packages, features, keywords plus exclude_* variants), VIN masks (vin_pattern), ranges (min_price, max_price, min_mileage, max_mileage, min_msrp, max_msrp, min_days_on_market, max_days_on_market), and geography (postal_code or latitude/longitude with radius, plus bbox for map viewports).
Closed-vocabulary filters reject unsupported values instead of returning a silent empty result. inventory_type accepts new, used, and certified; cpo is accepted as an alias for certified. keywords is for provenance/history tokens only: one_owner, clean_title, branded, and fleet. Discover open categorical values, such as trim, version, assembly_country, features, and options_packages, with /v1/facets before filtering.
Use fields to return specific public listing summary fields. The default response fields do not change unless fields is supplied. id and vin are always returned, and default includes the normal listing summary fieldset plus selected extras. Unknown fields are rejected:
fields values are:
vin_pattern to filter by one or more positions in a 17-character US VIN. Pass up to 10 comma-separated masks. VIN characters match themselves, ? matches exactly one VIN position, and * may appear only at the end. Short masks are treated as prefixes, so vin_pattern=1HG is equivalent to 1HG*. Examples: vin_pattern=1HG for WMI, vin_pattern=1HGCM826* for WMI plus VDS, and vin_pattern=???????J* for a specific eighth VIN character. VIN input is normalized to uppercase and may not contain I, O, or Q.
Sort listing collections with field names. Prefix a field with - for descending order. The default is sort=days_on_market, which returns newest listings first. Supported fields are days_on_market, price, miles, msrp, discount, and distance. discount_from_msrp is a signed fraction calculated as (price - combined_msrp) / combined_msrp; it uses combined MSRP, not base MSRP. Negative values are below MSRP. sort=discount returns the best discount from MSRP first. sort=distance requires postal_code or latitude/longitude.
inventory_status=active is the default. Use inventory_status=sold or sold_within_days=30 for sold inventory. A listing is sold only after it has been missing from the dealer’s inventory feed for at least three days and passed sold-quality checks; before then 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.
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 dealer feeds.
price is the dealer’s main advertised listing price when Visor has a usable value. It may or may not include fees, add-ons, incentives, taxes, registration, or other adjustments depending on how the dealer presents pricing. More detailed pricing information is coming soon.
Fetch one listing:
vehicle, with installed options under vehicle.build.options when requested.
Include price history or decoded installed options directly on listing search pages:
include=price_history adds a price_history array to each listing in the returned page. include=options adds an options array of { code, name, msrp } objects decoded from the listing’s option/package codes. Listing collection pages remain capped at 100 records and are priced as enriched listing search requests when either expansion is requested.
Facets
limit, offset, sort, fields, radius_id, columns, option_sort, and agnostic. The facets parameter is required; pass a comma-separated selection such as facets=make,model,price.
Categorical facets return up to 20 values by default. Use facet_value_limit to request a different per-facet value limit, up to 100. Values above 100 are rejected with validation_error; they are not silently clamped. Numeric range facets use fixed buckets and are not affected by facet_value_limit.
Supported facet names are make, model, inventory_type, year, trim, version, base_exterior_color, exterior_color, base_interior_color, interior_color, seating_capacity, doors, engine, state, drivetrain, assembly_location, assembly_country, transmission, fuel_type, body_type, cylinders, dealer_type, availability_status, options_packages, features, keywords, price, msrp, miles, and days_on_market.
Facet totals are returned at data.total. Categorical buckets are keyed by facet name under data.facets, numeric buckets are under data.range_facets, and numeric stats are under data.stats.
Facet buckets are sorted by count by default. Use metric to add one per-bucket aggregate while still returning count for sample-size context:
price, miles, msrp, days_on_market, and discount_from_msrp. Supported metric aggregates are mean, p5, p25, median, p75, and p95. Non-count metrics require exactly one categorical facet. Numeric range facets such as price, miles, msrp, and days_on_market keep their range-bucket behavior.
Facet sort accepts -count, count, -metric, and metric. It defaults to -count, even when metric is supplied. Buckets with fewer than 10 matching listings return metric.value: null with null_reason: insufficient_sample.
VIN Lookup
latest_listing. Dealer and photos are included on the latest listing by default. Request include=price_history for listing price changes and include=options for installed options in the build:
404 not_found_error.
With include=price_history, VIN price changes are returned at data.latest_listing.price_history. With include=options, installed options are returned at data.build.options.
Dealers
Search dealers:listing_count. Results include location summary fields, latitude/longitude, dealer type, normalized website, and represented franchise makes. Use dealer_id, state, country, type, make, and q to narrow results. The dealer_id filter accepts up to 100 comma-separated dealer IDs for direct profile lookup. The make filter matches represented franchise makes, not current inventory makes.
listing_count uses VIN-level listing deduplication and ownership assignment, so it can be lower than a raw dealer feed count when duplicate VIN evidence is attributed to another dealer.
Fetch one dealer:
phone and structured address when available. Dealer profiles can exist with listing_count: 0.
List inventory for one dealer:
404 not_found_error.
Use /v1/dealers/{dealer_id}/listings for single-dealer inventory. Use /v1/listings?dealer_id=id1,id2 for explicit multi-dealer listing search across up to 50 dealer IDs.
Dealer inventory endpoints return listings attributed to that dealer after VIN-level deduplication. A VIN observed in a dealer’s feed may be omitted when Freeway believes another dealer owns that listing.
Pagination
Collection endpoints uselimit and offset. The default limit is 50 and the maximum is 100. Values above 100 are rejected with validation_error; they are not silently clamped.
next_offset for the next page. It is null when the current page is the last page. total is counted for the same filters at request time and can change as inventory changes.
Usage And Billing Headers
Successful paid responses include:X-Usage-Cost-Micros is denominated in integer USD micros. 1000000 micros equals 1.00 USD. Postgres is the billing ledger authority; analytics exports may lag.
Successful /v1 responses also include account-level rate-limit headers:
Usage Summaries
Use/v1/usage to fetch daily billable usage buckets for the authenticated API account. This endpoint is not billable, requires the usage.read key scope, and is eventually consistent with the billing ledger.
metering_class=listing_search,vehicle_detail to filter the summary to specific usage classes.
Pricing
Pre-production billing uses prepaid dollar-denominated API credits. Design partner credits are granted during onboarding; no monthly platform fee or public volume discounts apply during pre-production. High-volume usage and bulk data licensing are handled on custom terms. Prices are per successful request, not per returned row. Collection endpoints can return up to 100 records per request. Successful zero-result searches are billable. Detail404 not_found_error responses are not billable.
| API usage type | Usage class | Price/request |
|---|---|---|
| Listing search | listing_search | $0.002 |
| Historical listing search | listing_search_historical | $0.004 |
| Dealer-filtered listing search | listing_search_dealer_filtered | $0.003 |
| Historical dealer-filtered listing search | listing_search_dealer_filtered_historical | $0.006 |
| Dealer inventory search | dealer_inventory_search | $0.003 |
| Historical dealer inventory search | dealer_inventory_search_historical | $0.006 |
| Enriched listing search | listing_search_enriched | $0.040 |
| Facet counts | facet_counts | $0.003 |
| Historical facet counts | facet_counts_historical | $0.006 |
| Vehicle detail | vehicle_detail | $0.003 |
| Enriched vehicle detail | vehicle_detail_enriched | $0.008 |
| Dealer lookup | dealer_lookup | $0.001 |
inventory_status=sold, sold_within_days, or snapshot_date.
Dealer-filtered listing pricing applies when /v1/listings uses the dealer_id filter. Pricing remains per successful page, not per dealer ID.
Enriched listing search pricing applies to listing collection requests with include=price_history and/or include=options. Pricing remains per successful page, not per listing, option, or price change event.
Enriched vehicle detail pricing applies to GET /v1/vins/{vin} and GET /v1/listings/{listing_id} when include=price_history and/or include=options is requested.
Rate Limits
The beta public API enforces Usage Tier rate limits at the API account level. Limits are shared by all API keys on the account, so creating more keys does not increase throughput.| Usage Tier | Requests / 10 seconds | Requests / 60 seconds |
|---|---|---|
| Tier 1 | 20 | 60 |
| Tier 2 | 100 | 100 |
| Tier 3 | 200 | 600 |
| Tier 4 | 500 | 3000 |
| Target Tier | Verified paid API credits | Days since first successful paid credit | Review |
|---|---|---|---|
| Tier 2 | $25 | 7 | Automatic when in good standing |
| Tier 3 | $150 | 14 | Automatic when in good standing |
| Tier 4 | $500 | 30 | Manual review required |
429 and include Retry-After when available. See Usage Tiers for upgrade behavior and limit semantics.
Error Examples
400 validation_error:
401 authentication_error:
402 billing_error:
404 not_found_error:
429 rate_limit_error:
503 platform_error:
