Skip to main content

Public Inventory Source

The inventory source fetches active dealer inventory from the Stellantis brand public web APIs (jeep.com, dodge.com, ramtrucks.com, chrysler.com). It is specific to the Stellantis project (projects/ai_stellantis).

Endpoint Pattern

https://www.<brand-domain>/hostd/inventory/getinventoryresults.json

Pagination uses pageNumber (1-based) and pageSize query params. Total record count is read from result.data.metadata.totalcount in the first page response.

Partitioning by dealer (100k offset cap)

The search returns only the first 100,000 results per query — pages past that offset return HTTP 500 (an HTML maintenance page, not JSON). A single high-volume modelYearCode (e.g. a Ram model year code reports ~100k nationwide) therefore cannot be retrieved by one nationwide query.

To capture everything, the fetch partitions by dealer: every vehicle belongs to exactly one dealer, so the asset queries small comma-joined dealerCodes chunks (DEALER_CHUNK_SIZE, default 10) per model year code and unions them — complete and duplicate-free, with each query far below the cap. Comma is the only multi-value separator the endpoint honors. The dealer list comes from the brand's dealer_locator raw asset, so the inventory asset declares two upstreams (vehicle_data_<brand> for model year codes, dealer_locator_<brand> for dealer codes). With dealerCodes set, zip/radius are required-but-ignored placeholders.

Required Environment Variables

VariableDefaultDescription
STELLANTIS_INVENTORY_ZIPUS geographic centerPlaceholder center ZIP (ignored when dealerCodes is set)
STELLANTIS_INVENTORY_RADIUSUS nationwide radiusPlaceholder radius in miles (ignored when dealerCodes is set)
STELLANTIS_INVENTORY_DEALER_CHUNK10Dealers per comma-joined dealerCodes query
STELLANTIS_INVENTORY_MODEL_WORKERS20Concurrent request pool size across all (model, chunk, page) requests
STELLANTIS_INVENTORY_THROTTLE_INTERVAL0.20Min seconds between requests pool-wide (~5 req/s)
STELLANTIS_INVENTORY_TIMEOUT60.0Per-request timeout in seconds (covers connect + read)
STELLANTIS_INVENTORY_MAX_RETRIES3Retries per request on transient errors / bot-block pages
STELLANTIS_INVENTORY_RETRY_BACKOFF2.0Initial backoff in seconds; doubles each attempt
STELLANTIS_INVENTORY_MAX_PER_MODEL(unset)Cap total records per query (dev/testing)

Authentication

No credentials required — the endpoint is a public API used by the brand consumer websites. However, it bot-blocks datacenter IPs (e.g. the production ECS egress) with HTTP 403 while serving residential IPs normally. Requests therefore go through AkamaiSessionFactory (ai_core.http): a curl_cffi browser TLS impersonation that seeds ak_bmsc / bm_sv cookies from the brand homepage and rotates the session on a block before retrying.

Known Data Quality Issues

Incorrect brand field on Jeep vehicles

The Jeep inventory API occasionally returns a small number of records (~7 per affected day) where the brand field contains a non-Stellantis value such as "Toyota", "Ford", or "Lexus". Inspection of the affected records confirms these are genuine Jeep vehicles — VINs start with 1C4 (Chrysler/Jeep WMI) and the Stellantis-internal extImage/intImage fields carry brand=J. The corrupted brand value originates in the Stellantis backend and is returned verbatim by the API.

Impact: COSY image URL generation requires a valid Stellantis brand. An unknown brand previously caused a KeyError crash that blocked the transformed asset for ~60 affected partition dates over the year.

Fix applied: make_cosy_image_urls in ai_stellantis/cosy.py validates the brand against the set of values accepted by the COSY generator (StellantisBrand Literal type). Records with an unrecognized brand are written to the output with null image URLs and a warning is logged; the partition does not fail.

If the upstream data quality improves or a reliable correction rule can be determined from the VIN WMI prefix, this behavior can be revisited.