Skip to main content

Discovery Contract — audi (us)

The vetting gate between discovery and coding. This file is the human narrative + probe evidence; the authoritative gate state lives in the sidecar discovery-contract.gate.json, validated by check_contract_gate.py. Keep this table in sync with the sidecar — every discovered endpoint/entity/FK in requirements must have a matching category:item gate, and every HARD row should read ✅ PASS or 🟡 OVERRIDE: <reason> (user-approved) before check_contract_gate.py passes and coding may begin. A Postman row may instead read 📦 MANUAL-IMPORT: <path> when the Postman MCP was unavailable and the collection was exported for hand-import — that state passes the gate but stays flagged. Probe markdown blocks are pasted in verbatim by public-api-contract-test.

  • OEM / market: audi / us
  • Discovered: 2026-07-09
  • Gate status: ✅ all hard gates green (Postman rows recorded live in the "Public OEM APIs" collection, 2026-07-09)

Gate summary

#GateEntity / paramStatusEvidence
1Pagination contractinventory✅ PASSpagination_probe (260/260, carline=s8l)
2Enumerator (model)models✅ PASSlive CarlineStructure flatten (36 codes / 75 catalog_ids)
3Enumerator (year)models✅ PASSCarlineStructure modelId.year (2026/2027)
4Enumerator (trim)models✅ PASSCarlineStructure carlines/trimlines (32/36)
5Enumerator (dealer)dealers✅ PASSenumerator_probe (315 matPrimaryCode)
6Multi-value filterinventory⬜ N/Apipeline sends criteria:[] — never combined
7Body shape / bot-blockinventory✅ PASSbody_shape_probe (n=15, 0% block)
8Body shape / bot-blockfeatures (configurator)✅ PASSbody_shape_probe (CatalogForModel, n=15)
9Data quality / plausibilityinventory✅ PASSdata_quality_probe (100 records)
10Data quality / plausibilitydealers✅ PASSdata_quality_probe (315 records, real lat/long)
11Data quality / plausibilitymodels✅ PASSdata_quality_probe (75 records)
12Data quality / plausibilityfeatures✅ PASSdata_quality_probe (207 records)
13Cross-source identity keyinventory→dealers✅ PASSmatPrimaryCode 45/45
14Cross-source identity keyinventory→models✅ PASSbare model_code (NOT composite)
15Cross-source identity keyinventory→features✅ PASSpr3_id shared namespace
16Cross-source identity keyfeatures→models✅ PASSmodel_catalog_id
17Real fixture (no synthetic)inventory✅ PASStests/data/onegraph_stockcarsearch_sample.json
18Real fixture (no synthetic)dealers✅ PASStests/data/pss_dealers_sample.json
19Real fixture (no synthetic)models✅ PASStests/data/onegraph_carlines_sample.json
20Real fixture (no synthetic)features✅ PASStests/data/catalog_for_model_sample.json
21Postman recordinventory✅ PASSPostman "Public OEM APIs" → Audi folder, request StockCarSearch — inventory (ingested) (30657947-142fad49-6805-4e2b-bc50-4a7482860501)
22Postman recorddealers✅ PASSPostman "Public OEM APIs" → Audi folder, request dealersByMarket — dealers (ingested) (30657947-77f50d5e-ca1b-4d3b-bf46-45c3fd11d3d8)
23Postman recordmodels✅ PASSPostman "Public OEM APIs" → Audi folder, request CarlineStructure — models (ingested) (30657947-8cea62b4-20c7-4ff5-a264-26695ef0eb76)
24Postman recordfeatures✅ PASSPostman "Public OEM APIs" → Audi folder, request CatalogForModel — features (ingested) (30657947-b2d48e26-9bad-4f3f-ae04-d366d7ba66f9)

Per-entity endpoints

EntityEndpoint (method + URL)Auth / protocolFixtureNotes
inventoryPOST https://omnigraph.audi.com/graphql (StockCarSearch)none; apollographql-client-name: fa-vlp-list-pageonegraph_stockcarsearch_sample.jsonnational, criteria:[], offset paging, resultNumber=52304, page-size ceiling 200
dealersPOST https://graphql.pss.audi.com/ (dealersByMarket)dynamic clientid header (market-context service)pss_dealers_sample.jsonone call per market A-<ISO alpha3>; 315 US dealers
modelsPOST https://omnigraph.audi.com/graphql (CarlineStructure)none; apollographql-client-name: audi-data-platformonegraph_carlines_sample.jsonsingle nested tree; drives features fan-out
featuresGET https://web-api.audi.com/vsapi/v1/us/en/CatalogForModel?model={id}nonecatalog_for_model_sample.jsonone GET per model_catalog_id derived from models

Cross-source identity / FK alignment (HARD)

Value-matched (not name-matched) join keys, verified against live data 2026-07-09.

FKReferencing entity.fieldTarget entity.fieldExample valueVerified
inventory→dealersinventory stockCar.dealer.iddealers matPrimaryCodeUSA01A23✅ 45/45 (PSS dealerId fails — extra brand letter)
inventory→modelsinventory stockCar.model.id.codemodels modelId.codeGUBAAY✅ 14/21 (bare code; composite model_catalog_id = 0/32)
inventory→featuresinventory feature prNumber.codefeatures id (PR3)C5J✅ shared PR-code namespace
features→modelsfeatures model_catalog_idmodels catalog_idFJBABY0_2026✅ by construction (per-model fetch)

Probe evidence

1. Pagination contract — inventory

Pagination contract — ✅ PASS

  • Endpoint: POST https://omnigraph.audi.com/graphql
  • Contract: offset via searchParameter.paging.offset + searchParameter.paging.limit, size 100
  • Termination: short/empty page
  • Completeness: fetched 260 unique records vs reported total 260 across 3 page(s).
  • Method: narrowed to criteria:[{"id":"carline","items":["s8l"]}] (260 vehicles) so the full result set fits the page budget. Offset advances (page 2 ≠ page 1); natural termination on the short 3rd page. National unfiltered resultNumber = 52304. Page-size ceiling = 200 (limit >= 250 returns a GRAPHQL subgraph error); the pipeline sends limit=100.

2–5. Enumerators (model / year / trim / dealer)

Enumerator (dealer) — ✅ PASS (enumerator_probe, live)

  • POST https://graphql.pss.audi.com/ enumerates 315 distinct matPrimaryCode values, e.g. ['USA01A17','USA01A23','USA01A26','USA01A27','USA01A29','USA01A30','USA01A31','USA01A32']. Single national dealersByMarket(market:"A-USA") call returns the complete set; iterate live.

Enumerator (model / year / trim) — ✅ PASS (live CarlineStructure flatten)

  • enumerator_probe cannot flatten Audi's 3-level-nested CarlineStructure tree (carlineGroups → carlines → trimlines → models), so these were verified by a live flatten on 2026-07-09: CarlineStructure (POST omnigraph.audi.com/graphql, client audi-data-platform) returns 36 distinct modelId.code, 75 model_catalog_id, 32 distinct carline ids / 36 carlines, model years 2026 + 2027, across 16 groups.
  • This IS the features fan-out driver (node a → node b): parse_model_entities consumes it live — no hardcoded lineup. year and trim are attributes of the same single call, not independent fan-out params. Cross-checked vs inventory StockCarSearch facets: modelCode (48), carline (33), model-year (9, incl. older/used stock).

6. Multi-value filter — inventory

N/A — the pipeline sends searchParameter.criteria:[] (one unfiltered national pass). No multi-value fan-out param is ever combined, so the contamination probe does not apply.

7–8. Body shape / bot-block

Body shape / bot-block (inventory) — ✅ PASS

  • Endpoint: POST https://omnigraph.audi.com/graphql — every 2xx (n=15) parsed as JSON, 0% block with and without a realistic UA. A realistic UA is not strictly required, but the source module sends ai_core.http.random_headers().

Body shape / bot-block (configurator / features) — ✅ PASS

  • Endpoint: GET https://web-api.audi.com/vsapi/v1/us/en/CatalogForModel?model=FJBABY0_2026 — every 2xx (n=15) parsed as JSON, 0% block with/without UA.

9–12. Data quality / plausibility

Data quality (inventory) — ✅ PASS — 100 live records; vin, id, dealer.id, model.id.code, carline.id all 0% implausible.

Data quality (dealers) — ✅ PASS — 315 live records; matPrimaryCode/name nonempty, latitude/longitude in-range and non-zero across all 315 (NOT the Hyundai 0.0 signature).

Data quality (models) — ✅ PASS — 75 live records; model_code, catalog_id, carline_id nonempty, model_year positive, 0% violations.

Data quality (features) — ✅ PASS — 207 live CatalogForModel equipment items (FJBABY0_2026); id (PR3 code) and name nonempty, 0% violations (189 distinct pr3 ids).

13–16. Cross-source identity keys

  • inventory→dealers: stockCar.dealer.id == PSS matPrimaryCode = 45/45 (100%). PSS dealerId matches 0/45 (carries an extra brand letter: USAA01A17 vs USA01A23). Stable key = matPrimaryCodedealer_mat_primary_code.
  • inventory→models: bare stockCar.model.id.code == modelId.code = 14/21 (the 7 unmatched are older-MY used/carryover stock absent from the current 2026/2027 catalog). The composite model_catalog_id value-matches 0/32 — inventory extensions/version differ from catalog — so the FK is bare model_code, not the composite (value-match, not name-match).
  • inventory→features: feature prNumber.code (PR3) and CatalogForModel id share the same 3-char PR-code namespace; stable feature key = pr3_id.
  • features→models: features are fetched per model_catalog_id derived from CarlineStructure, so feature.model_catalog_id == models.catalog_id exactly. Stable FK = model_catalog_id.

17–20. Real fixtures

EntityFixtureLive request
inventoryprojects/ai_audi/tests/data/onegraph_stockcarsearch_sample.jsonStockCarSearch (real VIN WAULSBF87RN010649)
dealersprojects/ai_audi/tests/data/pss_dealers_sample.jsondealersByMarket (matPrimaryCode USA01A17)
modelsprojects/ai_audi/tests/data/onegraph_carlines_sample.jsonCarlineStructure
featuresprojects/ai_audi/tests/data/catalog_for_model_sample.jsonCatalogForModel

Freshness (models / features)

  • models: live CarlineStructure (2026-07-09) returns MY2026 (current) + 2027 and the full current Audi USA nameplate set (32 carlines: Q3/Q5/Q6 e-tron/Q7/Q8, A3/A5/A6/A8, e-tron GT, plus S/RS variants). Endpoint actively maintained — migrated onegraphomnigraph 2026-06-26. Fresh, not stale-but-valid.
  • features: live CatalogForModel returns current equipment data for the same MY2026 model_catalog_ids (e.g. FJBABY0_2026 Q3 → 207 items). Tracks the current model set.

21–24. Postman records

Reconciled 2026-07-09 directly against the live "Public OEM APIs" collection (Audi folder, uid 30657947-4bc8f4a3-d3a9-4273-8fde-b1992a7b29bb) in the AutoIntel Workspace — no exported JSON files; the collection itself is the record of record. The Postman MCP still exposes no createCollectionFolder/deleteCollectionRequest/transfer tool in this workspace, so a dedicated "Legacy / Unused" subfolder could not be created and the 11 non-ingested requests already in the folder could not be moved or deleted; each was instead renamed with a [LEGACY / UNUSED] prefix and an explanatory description in place. updateCollectionRequest itself needed the collection's bare UUID (no {owner}- prefix) — passing the UID form (as the tool's own docstring implies) fails with a changeParentError.

EndpointEntityPostman request (id)
OmniGraph StockCarSearchinventoryStockCarSearch — inventory (ingested) (30657947-142fad49-6805-4e2b-bc50-4a7482860501)
PSS dealersByMarketdealersdealersByMarket — dealers (ingested) (30657947-77f50d5e-ca1b-4d3b-bf46-45c3fd11d3d8)
OmniGraph CarlineStructuremodelsCarlineStructure — models (ingested) (30657947-8cea62b4-20c7-4ff5-a264-26695ef0eb76)
Web-API CatalogForModelfeaturesCatalogForModel — features (ingested) (30657947-b2d48e26-9bad-4f3f-ae04-d366d7ba66f9)

11 other requests remain in the Audi folder (unmoved, due to the tool gap above) and are now labeled [LEGACY / UNUSED]: two old scs.audi.de pre-migration captures ("Fetch Inventory", "Vehicle Details"), the single-vehicle stockCar(...) query, the stockCarsType: USED variant, a cdbCategories/configuredCar investigation pair ("OneGraph Config", "Configuration") already resolved as dead ends, an image-render request, a duplicate single-VIN stockCarSearch capture, and two duplicate dealersByGeoLocation requests (a different operation from the ingested dealersByMarket). One stray empty-stub request ("Stock Search") was also flagged.

Overrides

No overrides. Every HARD gate is a green live probe or documented live verification.

GateOVERRIDE reasonApproved by