Skip to main content

Dealer Inspire Source

Dealer Inspire (Cars.com) builds dealer websites for several OEMs' franchise networks. The sites do not serve their own inventory: they query one Cars Commerce search service, and that service is what DealerInspireInventoryRawComponent reads.

assetdealers
mercedes/mbusa/raw/dealer_inspire_dealer_listings151
stellantis/us/raw/dealer_inspire_dealer_listings545

One component, one JSON file per OEM. The component is ai_public.components.dealer_inspire.DealerInspireInventoryRawComponent; the file is named by the dealers_json attribute in that OEM's defs.yaml and sits beside it.

Credentials

One API key, sent as x-api-key. It is not issued to us: every Dealer Inspire site ships it in its own page source, and the value is identical on all of them — the same key came back from every one of 693 sites read across two franchise networks. It is a constant in ai_public_api.dealer_providers.dealer_inspire, not an environment variable.

Nothing else is checked. The service accepts a request with no Origin, no Referer, and no cookies, and answers the same for every dealer.

The endpoint

POST https://websites-search.api.carscommerce.inc/api/v1/listings/{ccid}/search
{
"page": 1,
"perPage": 250,
"facetFilters": {"type_slug": ["New"]},
"requestedFields": ["vin", "stock", "manufacturer_model_code", "dealer.api_id", "..."]
}

Pages number from 1. perPage above 250 is rejected with a 400; the response carries data.total_vehicle_count and meta.pagination.total_pages.

requestedFields is not optional in practice. Omitted, the service returns a 12-field summary with no stock number, no dates and no options. The list the component sends is derived from the SEARCH_SERVICE_FIELD_MAP.requestedFields array the sites themselves ship, and covers manufacturer_model_code, model_number, date_in_stock, packages, features, mechanical, the full pricing block and extra_fields.factory_codes.

An entry may name a nested path — dealer.api_id, media.thumbnails — which prunes the response to that sub-key. Requesting media and extra_fields whole pulls in image URL lists and the SRP widget configuration, which are 83% of an unpruned listing and are of no use downstream; pruning them takes a listing from roughly 25 KB to 4 KB. extra_fields.factory_codes is kept because it carries the OEM's own factory option codes, and it is the reason extra_fields is requested at all.

Two fields the sites request are not requested here: history_report, whose Carfax keys are all null on new vehicles, and brochure, which was null on every listing sampled.

A sibling POST /api/v1/facets/{ccid} returns facet value counts, including the exact spelling of every type_slug. GET on either path is a 404 — the routes are POST-only.

Dealer identifiers

ccid is the Cars Commerce id that scopes a request to a site. It is inlined in the page source of the dealer's own site, so a plain fetch yields it:

curl -s --http2 -L --compressed -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" -H "Referer: https://www.google.com/" https://www.mbbhm.com/ | grep -o 'var SEARCH_SERVICE = {.*};'

The homepage carries the block, so sweeping a network does not need each dealer's inventory path. Space requests to a host: a sweep of 552 sites six at a time cleared 541 in six minutes, while three requests to one host four seconds apart drew the challenge.

The same block carries the API key, so a sweep that collects ccid also confirms the key has not rotated.

domain reaches no URL, query parameter or header — the component never sends it. It is in the file so an entry is readable and so a ccid can be traced back to the site it came from.

A ccid can serve more than one rooftop

A dealer group running one website has one ccid for the whole group, and that ccid returns every rooftop's vehicles, distinguished only by dealer.api_id on each listing. One site measured at 919 new vehicles spread across three rooftops.

How common this is varies by network — sampled at roughly a third of sites on one and the large majority on another — so it is the normal case to design for, not an edge case.

api_id itself is not a stable id shape. It is sometimes the OEM's own dealer code, sometimes an MPxxxx id, and sometimes a vanity string (klementcdj, Desert215SuperStore). Where a network issues numeric dealer codes, a large share of api_ids are literally those codes, which is the cheapest route to attribution when it holds.

Two consequences:

  • The file holds one entry per ccid. Two dealer codes sharing a site — one redirecting to the other's domain, say — would fetch the same vehicles twice if both were listed, so only one entry is kept. load_dealer_params raises on a repeated ccid rather than letting that happen silently.
  • _request_params carries ccid, perPage, type_slug and page — every part of the body that varies, under the body's own key, since nothing about a body-paginated request reaches the row otherwise. page is meaningless without the perPage it counts in, and both are component-configurable, so a row states the window it came from rather than assuming today's defaults. requestedFields is a module constant and is not repeated on every row.
  • The dealer code the file is keyed by is deliberately not recorded: it names the site queried, and a site serves whatever rooftops its group points at it, so stamping it would assert an ownership that does not hold. Attribute a listing to a rooftop by its own dealer.api_id.

The website challenge

A Dealer Inspire site answers a non-browser client with a 236 KB page titled Dealer Website in place of the real one. Sending Referer: https://www.google.com/ defeats it outright.

Nothing else does: HTTP/1.1, the inventory path instead of the homepage, a mobile Safari user agent and a Googlebot user agent were all refused on a host that answered immediately with the referer, and three passes sharing a cookie jar collected no cookies, so there is no clearance cookie to carry. It reads as a check that lets organic search traffic through.

This matters only when reading a site to capture its ccid. The component never fetches a dealer site — it talks to the search service, which challenges nothing.

Volume

One request per 250 new vehicles per dealer, one raw row per request. A site holding several rooftops is billed to whichever dealer code the file keys it under, so request counts track sites rather than dealers.

Not every Dealer Inspire site runs this service

A site can carry Dealer Inspire markers and still serve its inventory from somewhere else — a shared Algolia index and Motive (api.app.ridemotive.com) both appear under sites classified as Dealer Inspire. Those are separate platforms, not variants of this one: different endpoint, different auth, different payload. A site with no SEARCH_SERVICE block in its page source has nothing this component can read, whatever a provider survey calls it.