Skip to main content

Discovery Contract — bmw (global / 29 markets)

Retrospective contract — raw tier implemented before formal discovery. Gates populated from code review, local API probes (2026-06-20), GCP project inspection (ai-app-bmw), and source review of product-data-pipeline (S44-Automotive/product-data-pipeline@dev).

  • OEM / market: bmw / global (at, au, be, bg, ch, cz, de, dk, es, fi, fr, gr, hu, ie, in, it, jp, kr, lu, nl, no, pl, pt, ro, se, si, sk, th, za)
  • Discovered: 2026-06-20 (retrospective)
  • Gate status: ✅ unblocked — UCP and RIS bugs fixed in PR #504

Source overview

SourceEntityMarketsAuthStatus
Stolo (stolo-data-service.prod.stolo.eu-central-1.aws.bmw.cloud)inventoryall 29 except zaUser-Agent + X-Api-Key✅ headers fixed, ECS confirmation pending
UCP (prod.ucp.bmw.cloud)models + features + pricingall 29hardcoded SPA key✅ fixed in PR #504
c2b-services (c2b-services.bmw.com)dealers28 (not kr)public✅ confirmed
BMW Korea (bmw-dealer-locator.co.kr)dealerskr onlypublic (geo-blocked)🔴 geo-fenced
RIS (ris.api.bmw.com/m2m/sales/masterdata)optionscredential-scoped (currently sr-rs)OAuth2 machine2machine✅ fixed in PR #504
BMW SA BFF (buy.bmw.co.za)inventoryza onlyanonymous JWT✅ confirmed locally

Gate summary

#GateEntityStatusEvidence
1Paginationstolo_inventory🟡 OVERRIDEstartIndex/pageSize confirmed in product-data-pipeline source
2Enumerator (model_range)stolo_inventory🟡 OVERRIDEFacets aggregate → MARKETING_MODEL_RANGE; confirmed 200 locally
3Enumerator (drive_type)stolo_inventory🟡 OVERRIDEDrive-type fan-out for ranges >1200; confirmed in source
4Enumerator (model_id)ucp_model_details🟡 OVERRIDEUCP matrix drives fan-out; fixed in PR #504
5Enumerator (ris_model_id)ris_options🟡 OVERRIDE/vehicle-configurations/v1/models; fixed in PR #504
6Multi-valuestolo_inventory✅ N/AOne model_range per request
7Body shapestolo✅ PASSX-Api-Key added; 200 for de-de/ko-kr/en-in locally; ZA=404 (not a Stolo market)
8Body shapeucp✅ PASSEndpoint fixed to prod.ucp.bmw.cloud; 200 confirmed locally (PR #504)
9Body shapec2b_dealers✅ PASS200 from local + ECS; DE=652, ZA=67, AU=56
10Body shaperis✅ PASSHostname + scope fixed in PR #504; 200 confirmed on branch deployment
11Body shapeza_inventory✅ PASS200 locally; 84 vehicles via buy.bmw.co.za BFF
12Data qualityc2b_dealers✅ PASSZA envelope identical to DE; no schema divergence
13Data qualityza_inventory✅ PASS84 vehicles; id/vin/model/title/price/bodyType all present
14Fixturestolo_inventory_facets⬜ TODOUnblocked post-header-fix; needs branch deployment capture
15Fixturestolo_inventory⬜ TODOSame — needs branch deployment
16Fixtureucp_model_matrix⬜ TODOEndpoint fixed; needs capture
17Fixtureucp_model_details⬜ TODOEndpoint fixed; needs capture
18Fixtureucp_pricing⬜ TODOEndpoint fixed; needs capture
19Fixturec2b_dealers_de✅ PASStests/data/bmw_c2b_dealers_de_sample.json
20Fixturec2b_dealers_za✅ PASStests/data/bmw_c2b_dealers_za_sample.json
21Fixturekorea_dealers🔴 FAILGeo-fenced; empty body outside Korean IP space
22Fixtureris_model_ids⬜ TODOHostname/scope fixed; needs VPC capture
23Fixtureris_options⬜ TODOHostname/scope fixed; needs VPC capture
24Fixtureza_inventory⬜ TODOEndpoint confirmed; needs branch deployment capture
25Postman recordstolo✅ PASSCollection populated in PR #504
26Postman recorducp✅ PASSCollection populated in PR #504
27Postman recordc2b_dealers✅ PASSCollection populated in PR #504
28Postman recordris✅ PASSCollection populated in PR #504
29Postman recordza_inventory✅ PASSCollection populated in PR #504

Per-entity endpoints

EntityEndpoint (method + URL)AuthFixtureNotes
stolo_inventory_facetsPOST stolo-data-service.prod.stolo.eu-central-1.aws.bmw.cloud/vehiclesearch/aggregate/{locale}/stocklocatorUser-Agent + X-Api-Key⬜ pendingReturns MARKETING_SERIES→MARKETING_MODEL_RANGE facet tree
stolo_inventoryPOST …/vehiclesearch/search/{locale}/stocklocatorUser-Agent + X-Api-Key⬜ pendingPaginates via startIndex/maxResults; cap 1200; fan-out per model_range
ucp_model_matrixGET prod.ucp.bmw.cloud/model-matrices/vehicle-trees/{vehicle-tree}/sources/{source}/brands/{brand}/countries/{country}/effect-dates/{date}/order-dates/{date}SPA key❌ pendingvehicle-tree: connext-bmw (std) or connext-bmw-datafox (in/rs/th/tr)
ucp_model_detailsGET prod.ucp.bmw.cloud/localisations/overridden-vehicle-data/sources/{source}/brands/{brand}/countries/{country}/effect-dates/{date}/order-dates/{date}/applications/{application}/models/{modelCode}/options/languages/{language}SPA key❌ pendingapplication: connext (std) or connext-datafox
ucp_pricingPOST prod.ucp.bmw.cloud/pricing/calculation/public-calculation/price-lists/{source},con/brands/{brand}/countries/{country}SPA key❌ pendingExtra params for CO2/NOx/Hubraum in AT/ES/FI/GR/IE/NL/NO/PT
c2b_dealersGET c2b-services.bmw.com/c2b-localsearch/services/api/v4/clients/BMWSTAGE2_DLO/-/poispublicbmw_c2b_dealers_de_sample.jsonParams: brand, language, country, lat=0, lng=0, maxResults=700
korea_dealersGET bmw-dealer-locator.co.kr/api/getListpublic (geo-block)❌ pendingKorea only; geo-fenced
ris_model_idsGET ris.api.bmw.com/m2m/sales/masterdata/vehicle-configurations/v1/modelsOAuth2 machine2machine + apikey❌ pendingdatafox markets only (in, th); params: brand, country, source=datafox
ris_optionsGET ris.api.bmw.com/m2m/sales/masterdata/vehicle-configurations/v1/models/{model_id}/optionsOAuth2 + apikey❌ pendingsr-rs only
za_inventoryPOST buy.bmw.co.za/api/product/productsanonymous JWT from /api/load-page/bmw⬜ pendinghandle=bto, storefrontCode=bmw_vehicle, first=500; 84 vehicles

Fixed bugs (PR #504)

All bugs listed below were fixed in PR #504 and are kept here for historical reference.

  • UCP wrong endpoint (gates 8, 16–18): Was using api.bmw.com; corrected to prod.ucp.bmw.cloud with brand/country/date path structure and Akamai session for WAF bypass.
  • RIS wrong hostname + scope (gates 10, 22–23): Was ris.bmwgroup.net with scope=openid; corrected to ris.api.bmw.com/m2m/sales/masterdata with scope=machine2machine.
  • Stolo ZA not a supported market: en-za returns 404 from Stolo; replaced by BmwZaInventoryRawComponent using the BMW SA BFF (buy.bmw.co.za).

South Africa (za) status

SourceStatus
ZA inventory (buy.bmw.co.za BFF)✅ Implemented — 84 vehicles, anonymous JWT auth
C2B dealers✅ Confirmed — 67 dealers
Stolo❌ Not supported — 404
UCP models/pricing⬜ Pending UCP endpoint fix

Cross-source identity / FK alignment

Not applicable at raw tier. FK alignment is the responsibility of the transformed tier.

Overrides

GateOverride reasonApproved by
1 — PaginationConfirmed in product-data-pipeline source; startIndex/pageSize contract provenpmcguire
2 — Enumerator (model_range)Locally confirmed 200 with correct Stolo headers; facets aggregate returns correct treepmcguire
3 — Enumerator (drive_type)Pattern confirmed in product-data-pipeline sourcepmcguire
4 — Enumerator (model_id)UCP matrix structure confirmed in product-data-pipeline source; endpoint fix neededpmcguire
5 — Enumerator (ris_model_id)RIS model IDs endpoint confirmed in product-data-pipeline source; hostname fix neededpmcguire