BMW Global Public API Sources
BMW's global pipeline covers 29 markets across six source systems.
Postman collection — BMW public APIs
Endpoint Overview
| # | Source | Entity | Markets | Auth | Status |
|---|---|---|---|---|---|
| 1 | Stolo (stolo-data-service.prod.stolo.eu-central-1.aws.bmw.cloud) | Inventory | 28 (all except za) | User-Agent + X-Api-Key | Confirmed — headers fixed |
| 2 | UCP (prod.ucp.bmw.cloud) | Models + features + pricing | All 29 | Hardcoded SPA key | Confirmed |
| 3 | c2b-services (c2b-services.bmw.com) | Dealers | 28 (all except kr) | Public | Confirmed — DE=652, ZA=67, AU=56 |
| 4 | BMW Korea (bmw-dealer-locator.co.kr) | Dealers | kr only | Public (geo-blocked) | Geo-fenced outside Korean IPs |
| 5 | RIS (ris.api.bmw.com/m2m/sales/masterdata) | Model features | in, rs, th, tr (datafox markets) | OAuth2 machine2machine + apikey | 403 pending credential provision |
| 6 | BMW SA BFF (buy.bmw.co.za) | Inventory | za only | Anonymous JWT | Confirmed — 84 vehicles |
1. Stolo — Inventory
BMW's stock-locator service. Two endpoints: a facets aggregate for enumerating model ranges, and a paginated inventory search filtered per model range.
Base URL: https://stolo-data-service.prod.stolo.eu-central-1.aws.bmw.cloud
Authentication
The Stolo WAF requires a browser-shaped User-Agent and a static X-Api-Key
header. Requests without the key return 403.
| Header | Value |
|---|---|
User-Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 |
X-Api-Key | 7f665f5b3cb8fe8e83293052367c575f666078b87570d5557f02f248ec98 |
Content-Type | application/json |
Cache-Control | no-cache, no-store, must-revalidate |
1a. Inventory Facets Aggregate
POST /vehiclesearch/aggregate/{locale}/{stock_resource}
Returns a MARKETING_SERIES → MARKETING_MODEL_RANGE facet tree used to enumerate
model ranges before the inventory fan-out.
Path params:
{locale}— IETF locale tag, e.g.de-de,ko-kr,en-in{stock_resource}—stocklocatorfor most markets;odmah_dostupna_vozilafor Serbia (sr-rs)
Query params: brand=BMW
Request body:
{
"searchContext": [{}],
"resultsContext": {"sort": [{"by": "MODEL_DESCRIPTION", "order": "ASC"}]}
}
Response: {aggregateGeneric: [{name: "MARKETING_SERIES", values: [...]}]}
Walk aggregateGeneric → filter name == "MARKETING_SERIES" → explode values
→ filter inner name == "MARKETING_MODEL_RANGE" → collect values[].name.
Observed counts: de-de = 52 model ranges, ko-kr = 21, en-in = 13.
ZA note: en-za returns 404 — ZA is not a Stolo market. ZA inventory is
served by the BMW SA BFF (buy.bmw.co.za).
1b. Inventory Search (Paginated)
POST /vehiclesearch/search/{locale}/{stock_resource}
Paginated vehicle inventory filtered to one model range (and optionally a drive type).
Query params:
| Param | Value |
|---|---|
maxResults | 12 (page size) |
startIndex | 0, 12, 24, … up to 1200 |
brand | BMW |
Request body — single model range:
{
"searchContext": [{"model": {"marketingModelRange": {"value": ["BMW 1 Series"]}}}],
"resultsContext": {"sort": [{"by": "MODEL_DESCRIPTION", "order": "ASC"}]}
}
Request body — model range + drive type filter (oversize ranges):
{
"searchContext": [
{
"model": {"marketingModelRange": {"value": ["BMW 5 Series"]}},
"marketingDriveType": {"value": ["Plug-in Hybrid"]}
}
],
"resultsContext": {"sort": [{"by": "MODEL_DESCRIPTION", "order": "ASC"}]}
}
Pagination: metadata.totalCount gives the total. Page size = 12,
startIndex increments by 12. Hard cap: startIndex <= 1200. Ranges with
totalCount > 1200 are split by MARKETING_DRIVE_TYPE from a secondary
aggregate call before pagination.
Rate limiting: Stolo's WAF enforces roughly 0.9 req/s sustained. A shared
throttle at ~0.8 req/s (1.25s interval) keeps requests under the refill rate.
429 responses include a Retry-After header.
2. UCP — Models, Features, and Pricing
BMW's Universal Configurator Platform. Three endpoint families: model matrix, per-model feature/option data, and per-model pricing.
Base URL: https://prod.ucp.bmw.cloud
Authentication
Hardcoded SPA API key in x-api-key header. Browser-shaped User-Agent required
for the model matrix (Akamai-protected for some market/brand pairs).
| Header | Value |
|---|---|
x-api-key | OmFpaEFpV0VUaUlrWTJ2Tnp0ZGdiUTd1NDhxR3JOcHRacXg1UWQK |
User-Agent | (same browser UA as Stolo) |
Market variants
| Country set | vehicle-tree | source | application |
|---|---|---|---|
| Standard (all except in, rs, th, tr) | connext-bmw | pcaso | connext |
| Datafox (in, rs, th, tr) | connext-bmw-datafox | datafox | connext-datafox |
Two brand calls per locale: bmwCar and bmwi.
2a. Model Matrix
GET /model-matrices/vehicle-trees/{vehicle_tree}/sources/{source}/brands/{brand}/countries/{country}/effect-dates/{date}/order-dates/{date}
Query params: future-models=true&closest-fallback=true
Response: A JSON object keyed by series name. Each series has a modelRanges
dict; each model range has a models dict keyed by model code. Top-level also
includes closestEffectDate and closestOrderDate string keys (non-series data
to skip). The model codes from this response drive the model_details and pricing
fan-outs.
2b. Model Details (Per-model Features/Options)
GET /localisations/overridden-vehicle-data/sources/{source}/brands/{brand}/countries/{country}/effect-dates/{date}/order-dates/{date}/applications/{application}/models/{model_id}/options/languages/{language}
Response: {option_code: {option: str, std: bool, ...}}. All keys =
available options; keys where std=true = selected options.
404 behavior: Returns 404 when no overridden data exists for that model — this is suppressed (treated as empty, not a failure), matching the upstream product-data-pipeline reference.
2c. Pricing (Per-model Calculation)
POST /pricing/calculation/public-calculation/price-lists/{source},con/brands/{brand}/countries/{country}
Request body:
{
"settings": {
"priceTree": "DEFAULT",
"ignoreInvalidOptionCodes": true,
"ignoreOptionsWithUndefinedPrices": true,
"roundingScale": 1
},
"validityDates": {"taxDate": "2026-06-25", "effectDate": "2026-06-25"},
"configuration": {
"model": "{model_id}",
"availableOptions": ["P0300", "S0301"],
"selectedOptions": ["P0300"]
}
}
Country-specific additional params (in additionalParams body field):
| Countries | Required param |
|---|---|
| AT, ES, FI, GR, IE, NL, NO, PT | emission.wltp.co2Value |
| IE, PT | emission.particle.noxValue, emission.particle.particleMass, emission.particle.particleMassChargeSustaining |
| PT, TR | otd2.C_HUBRAUM.targetValue |
Models with no available options are skipped. 404 is suppressed.
3. C2B Dealers
BMW's global dealer locator service. Public, no auth required.
URL: GET https://c2b-services.bmw.com/c2b-localsearch/services/api/v4/clients/BMWSTAGE2_DLO/-/pois
Query params:
| Param | Value |
|---|---|
brand | BMW_BMWM |
category | BM |
language | market language, e.g. de, en |
country | ISO-2 uppercase, e.g. DE, ZA |
lat | 0 |
lng | 0 |
maxResults | 700 |
showAll | true |
unit | km |
cached | off |
lat=0&lng=0 with showAll=true returns all dealers regardless of location.
maxResults=700 covers the largest market (DE = 652 dealers).
Response envelope: {status, translation, metadata, data: {pois: [...]}, count}
POI fields: key, name, countryCode, country, state, city,
postalCode, street, additionalStreet, lat, lng, dist, oh, category,
attributes (includes distributionPartnerId, outletId, agDealerCode,
homepage, phone, fax, mail, portfolioCode, nickname, businessPartnerId).
Market coverage: 28 of 29 markets — all except kr (Korea), which has its
own geo-fenced endpoint (see Section 4).
Sample response — DE (652 dealers, trimmed to 3)
{
"status": {
"key": null,
"type": "OK",
"detail": null,
"subsystem": null,
"messages": null,
"logKey": null
},
"translation": {},
"metadata": {
"serviceVersion": "4.0",
"lists": null,
"colNames": []
},
"data": {
"pois": [
{
"key": "00131_2",
"name": "Autohaus Karl + Co. GmbH & Co. KG",
"countryCode": "DE",
"country": "Deutschland",
"state": null,
"city": "Wiesbaden",
"postalCode": "65203",
"street": "Carl-Bosch-Str. 6",
"additionalStreet": "",
"settlement": null,
"lat": 50.042728424072266,
"lng": 8.22134017944336,
"dist": -1.0,
"oh": "[]",
"category": "MINI",
"attributes": {
"distributionPartnerId": "00131",
"distributionCode": "EH",
"outletId": "2",
"ownerId": "01822",
"tradeRegisterName": "Mainz",
"tradeRegisterNumber": "HRA 1983",
"dealerLogoURL": null,
"homepage": "https://www.autohaus-krah-enders.de/",
"phone": "+49-611-278090",
"fax": "+49-611-2780939",
"mail": "info@bmw-karl-co.de",
"facebookPlace": "",
"agDealerCode": "03910",
"domesticDealerNumber": "",
"telephoneAreaCode": "+49-611-278090",
"faxAreaCode": "+49-611-2780939",
"portfolioCode": "MINI",
"nickname": "Karl",
"nicknameLocal": "Karl",
"additionalName": "GmbH & Co. KG",
"additionalNameLocal": "GmbH & Co. KG",
"businessPartnerId": "00000114",
"rfSupportedEmail": {
"RFO": "SVYqClDv8eSDtbimfagblVlv6xYvUKqaaMa5rG+eP/SYoEleH8J7GH+9vL6wubPKcZg2BhIxZfJxRoGM9JZDo6+WfA==",
"RFA": "SVYqe3RIrxAhI5m4fqZaG9MxqA7WMJi3KMZ5iAaS3JYKWhTsLecjRXMRfSzKaA7PU2CI",
"RFC": "SVYqlXECeI14WJTBSOVvoDucAty8LftHrP4hzoYE0jlK1+aKJuwAP6Yf4KTS0o5NZmvq",
"RFS": "SVYqED3XZ9uoL5GTiSs8AJsizJe7O7ilxoz+ANpUTKy0jAor/lfJ8nQCe6KuetQUmR6H"
},
"rfSupportedURL": {
"RFS": "SVYqHK/JIPhksNflyWtoMKW6PBTNfPIarO/lR1Bi5pqqiP4NpyxT1NoQ1VpqSunLnkxJm19kADNgJh7la/FqzjQkdo/QkrQ2wp6aISUcjVjc7XMHB5QTCBTLHUy8wR6z0bkh"
},
"naviPublished": true,
"businessTypeCodes": [
"BB",
"CA",
"CS",
"EC",
"ES",
"GV",
"NO",
"PR",
"PV",
"SP"
],
"distributionBranches": [
"G",
"F",
"T"
],
"outletTypes": [
"FU"
],
"requestServices": [
"RFA",
"RFC",
"RFI",
"RFO",
"RFS",
"SLG",
"STL",
"TDA"
],
"services": [],
"businessRelations": [
"BB_G",
"CA_F",
"CS_F",
"EC_G",
"ES_F",
"GV_G",
"NO_T",
"NO_F",
"PR_G",
"PV_F",
"SP_F"
],
"onlineSales": [
{
"salesType": "CAR_USED",
"contact": {
"phone": "+49-611-2780966",
"email": "wiesbaden@karlco.lead.carzilla.de"
}
}
]
}
},
{
"key": "00120_8",
"name": "AH Rhein Würzburg Zw.-Nl. der AH Heermann u. Rhein GmbH",
"countryCode": "DE",
"country": "Deutschland",
"state": null,
"city": "Würzburg",
"postalCode": "97076",
"street": "Louis-Pasteur-Str. 14",
"additionalStreet": "",
"settlement": null,
"lat": 49.79352951049805,
"lng": 9.998310089111328,
"dist": -1.0,
"oh": "[]",
"category": "MINI",
"attributes": {
"distributionPartnerId": "00120",
"distributionCode": "EH",
"outletId": "8",
"ownerId": "00120",
"tradeRegisterName": "Stuttgart",
"tradeRegisterNumber": "HRB 100287",
"dealerLogoURL": null,
"homepage": "https://www.rhein-bmw.de/",
"phone": "+49-931-278850",
"fax": "+49-931-2788585",
"mail": "info@rhein-wuerzburg.de",
"facebookPlace": "",
"agDealerCode": "02766",
"domesticDealerNumber": "",
"telephoneAreaCode": "+49-931-278850",
"faxAreaCode": "+49-931-2788585",
"portfolioCode": "MINI",
"nickname": "Rhein Würzburg",
"nicknameLocal": "Rhein Würzburg",
"additionalName": "AH Heermann u. Rhein GmbH",
"additionalNameLocal": "AH Heermann u. Rhein GmbH",
"businessPartnerId": "00002100",
"rfSupportedEmail": {
"RFO": "SVYqJxVmiKKiowLJ6qizqQ3O6UGSFQ+jwyzBanF3TWQI/PXCG1jVvZ8jo3t04CWBBS5c6yWViltlzA9SdGQ6llOu7Q==",
"RFA": "SVYqT0qVH3Kn9zRJosZy3enoh9Eg2moKYhS/hTziFiuEWwUmQWzCXcC+9LyX6DXDZHSO",
"RFC": "SVYqsVWO71yrTRsCujvXwSuyqrgmCnAixNoBNUzVKkyVv6rnxkhHWIJC2cP/nZpy8UgI",
"RFS": "SVYqn8qL+Ln1u+qzjiudnGPP4xGu8rSUL0QbpH3gYaJFNoEdBrbBJfjdbGR1RQHu45Fe"
},
"rfSupportedURL": {
"RFS": "SVYqt9/oqlueCFfL4kpGlu+B5HxZROFdpWGlpoQr2CBPlaoI5bTybsPbSFekhD0LdXKVjXJwx/lCujhHzQBYjgEktQxXZiTP9tDqurfKRvpLIT7/L1cimkvq3+enCrGmuNh/"
},
"naviPublished": true,
"businessTypeCodes": [
"BB",
"CA",
"CS",
"EC",
"ES",
"GV",
"MS",
"NO",
"PR",
"PV",
"SP"
],
"distributionBranches": [
"G",
"F",
"T"
],
"outletTypes": [
"FU"
],
"requestServices": [
"RFA",
"RFC",
"RFI",
"RFO",
"RFS",
"SLG",
"STL",
"TDA"
],
"services": [],
"businessRelations": [
"BB_G",
"CA_F",
"CS_F",
"EC_G",
"ES_F",
"GV_G",
"MS_T",
"NO_T",
"NO_F",
"PR_G",
"PV_F",
"SP_F"
],
"onlineSales": [
{
"salesType": "CAR_NEW",
"contact": {
"email": "markus.stumpf@rhein-wuerzburg.de"
}
},
{
"salesType": "CAR_USED",
"contact": {
"phone": "+49-931-87098122",
"email": "rhein-wuerzburg.verkauf@autocrm.de"
}
}
]
}
},
{
"key": "00116_1",
"name": "Auto-Leebmann GmbH",
"countryCode": "DE",
"country": "Deutschland",
"state": null,
"city": "Passau",
"postalCode": "94036",
"street": "Traminer Str. 1",
"additionalStreet": "",
"settlement": null,
"lat": 48.5546875,
"lng": 13.416739463806152,
"dist": -1.0,
"oh": "[]",
"category": "MINI",
"attributes": {
"distributionPartnerId": "00116",
"distributionCode": "EH",
"outletId": "1",
"ownerId": "00116",
"tradeRegisterName": "Passau",
"tradeRegisterNumber": "HRB 4377",
"dealerLogoURL": null,
"homepage": "https://www.leebmann.de/bmw",
"phone": "+49-851-700101",
"fax": "+49-851-700211",
"mail": "info@leebmann.de",
"facebookPlace": "",
"agDealerCode": "00116",
"domesticDealerNumber": "",
"telephoneAreaCode": "+49-851-700101",
"faxAreaCode": "+49-851-700211",
"portfolioCode": "MINI",
"nickname": "Leebmann",
"nicknameLocal": "Leebmann",
"additionalName": "",
"additionalNameLocal": "",
"businessPartnerId": "00000089",
"rfSupportedEmail": {
"RFO": "SVYqCSqT2K/++AX2TwqkZgETZwGeXtfzGxaS6feCldtzs3kymXrddd9v+cjuFp3a3tPd",
"RFA": "SVYqd9Z8Z5ZGyqHUl+uwvSQN30sN0ay9293+eT3KK5A9eWLeqQLKI+yg7sl3u/iVLsv/",
"RFC": "SVYqnOsdFWE6lxKDZS9um7t03mDvnlw1kYojRsFHJpiCGYcwQsFeM9xb5s5tjoAMNtE9",
"RFS": "SVYquhRGACnzpBA+VOY0ZCyd3cVGyQIbFeUxVbcSjioL8mooimBglAS/xrrdZp/dGZig"
},
"rfSupportedURL": {
"RFS": "SVYq+Wsu6HoVM6leAoCd5gsmchR4BMsvphmDyy3mj5W56AiRW6wcp8B+1DsyWXNMzgVryiwk54Kn6J3+gDHAuA1ICfwIx65IE5zbi5f683XitmwjGBtAy78paXneV9DN6zGY"
},
"naviPublished": true,
"businessTypeCodes": [
"BB",
"CA",
"CS",
"EC",
"ES",
"GA",
"GV",
"MS",
"NO",
"PR",
"PV",
"SP"
],
"distributionBranches": [
"G",
"F",
"T"
],
"outletTypes": [
"FU"
],
"requestServices": [
"RFA",
"RFC",
"RFI",
"RFO",
"RFS",
"SLG",
"STL",
"TDA"
],
"services": [],
"businessRelations": [
"BB_G",
"CA_F",
"CS_F",
"EC_G",
"ES_F",
"GA_F",
"GV_G",
"MS_T",
"NO_T",
"NO_F",
"PR_G",
"PV_F",
"SP_F"
],
"onlineSales": [
{
"salesType": "CAR_USED",
"contact": {
"phone": "+49-851-700101",
"email": "info@leebmann.de"
}
}
]
}
}
]
},
"count": 1344
}
Sample response — ZA (67 dealers, trimmed to 3)
{
"status": {
"key": null,
"type": "OK",
"detail": null,
"subsystem": null,
"messages": null,
"logKey": null
},
"translation": {},
"metadata": {
"serviceVersion": "4.0",
"lists": null,
"colNames": []
},
"data": {
"pois": [
{
"key": "02487_1",
"name": "BMW Ermelo",
"countryCode": "ZA",
"country": "South Africa",
"state": "Mpumalanga",
"city": "Ermelo",
"postalCode": "2351",
"street": "114 Kerk Street",
"additionalStreet": "",
"settlement": "Ermelo",
"lat": -26.51883316040039,
"lng": 29.984800338745117,
"dist": -1.0,
"oh": "[]",
"category": "BMW",
"attributes": {
"distributionPartnerId": "02487",
"distributionCode": "EH",
"outletId": "1",
"ownerId": "02487",
"tradeRegisterName": null,
"tradeRegisterNumber": null,
"dealerLogoURL": null,
"homepage": "https://www.bmw.co.za/ermelo",
"phone": "+27-17-8112242",
"fax": "+27-17-8191313",
"mail": "info@autobmw.co.za",
"facebookPlace": "",
"agDealerCode": "02487",
"domesticDealerNumber": "",
"telephoneAreaCode": "+27-17-8112242",
"faxAreaCode": "+27-17-8191313",
"portfolioCode": "BMW",
"nickname": "BMW Ermelo",
"nicknameLocal": "BMW Ermelo",
"additionalName": "",
"additionalNameLocal": "",
"businessPartnerId": "00001819",
"rfSupportedEmail": {},
"rfSupportedURL": {},
"naviPublished": true,
"businessTypeCodes": [
"MC",
"NO",
"CR",
"HV",
"BA",
"RB"
],
"distributionBranches": [
"F",
"T"
],
"outletTypes": [
"FU"
],
"requestServices": [],
"services": [
"RB",
"CR",
"HV",
"BA"
],
"businessRelations": [
"MC_F",
"NO_T",
"NO_F",
"CR_T",
"HV_T",
"BA_T",
"RB_T"
],
"onlineSales": []
}
},
{
"key": "21819_2",
"name": "Service Fast Lane [Potchefstroom]",
"countryCode": "ZA",
"country": "South Africa",
"state": null,
"city": "Potchefstroom",
"postalCode": "2520",
"street": "66 Walter Sisulu lane",
"additionalStreet": "",
"settlement": null,
"lat": -26.708539962768555,
"lng": 27.097679138183594,
"dist": -1.0,
"oh": "[]",
"category": "MINI",
"attributes": {
"distributionPartnerId": "21819",
"distributionCode": "EH",
"outletId": "2",
"ownerId": "21819",
"tradeRegisterName": null,
"tradeRegisterNumber": null,
"dealerLogoURL": null,
"homepage": "https://www.bmw.co.za/klerksdorp",
"phone": "+27-18-0111888",
"fax": "+27-18-4622842",
"mail": "ggh.reception@teamdaly.co.za",
"facebookPlace": "",
"agDealerCode": "51797",
"domesticDealerNumber": "",
"telephoneAreaCode": "+27-18-0111888",
"faxAreaCode": "+27-18-4622842",
"portfolioCode": "MINI",
"nickname": "",
"nicknameLocal": "",
"additionalName": "",
"additionalNameLocal": "",
"businessPartnerId": "00764705",
"rfSupportedEmail": {},
"rfSupportedURL": {},
"naviPublished": true,
"businessTypeCodes": [
"NO"
],
"distributionBranches": [
"T"
],
"outletTypes": [
"FL"
],
"requestServices": [],
"services": [],
"businessRelations": [
"NO_T"
],
"onlineSales": []
}
},
{
"key": "33519_1",
"name": "BMW Century City",
"countryCode": "ZA",
"country": "South Africa",
"state": "Western Cape",
"city": "Cape Town",
"postalCode": "7441",
"street": "1 Century Way, Century City",
"additionalStreet": "",
"settlement": "Milnerton",
"lat": -33.8927001953125,
"lng": 18.504409790039062,
"dist": -1.0,
"oh": "[]",
"category": "MINI",
"attributes": {
"distributionPartnerId": "33519",
"distributionCode": "EH",
"outletId": "1",
"ownerId": "27191",
"tradeRegisterName": null,
"tradeRegisterNumber": null,
"dealerLogoURL": null,
"homepage": "https://www.bmw.co.za/en/retailers-pages/bmw_century_city.html",
"phone": "+27-21-5256000",
"fax": "+27-86-6877363",
"mail": "smgcpt@smg.co.za",
"facebookPlace": "",
"agDealerCode": "33519",
"domesticDealerNumber": "",
"telephoneAreaCode": "+27-21-5256000",
"faxAreaCode": "+27-86-6877363",
"portfolioCode": "MINI",
"nickname": "BMW Century City",
"nicknameLocal": "BMW Century City",
"additionalName": "",
"additionalNameLocal": "",
"businessPartnerId": "00198185",
"rfSupportedEmail": {},
"rfSupportedURL": {},
"naviPublished": true,
"businessTypeCodes": [
"NO"
],
"distributionBranches": [
"T"
],
"outletTypes": [
"SE"
],
"requestServices": [],
"services": [],
"businessRelations": [
"NO_T"
],
"onlineSales": []
}
}
]
},
"count": 144
}
4. BMW Korea Dealers (Geo-fenced)
URL: GET https://www.bmw-dealer-locator.co.kr/api/getList
No query parameters required. No auth required. Returns dealer list for Korea.
Availability: Geo-fenced — returns an empty body outside Korean IP space. Fixture capture requires a Korean IP or proxy.
5. RIS — Model Features (Datafox Markets Only)
BMW's Regional Information System. Covers datafox markets only: in, rs, th,
tr. The API key provisioned for this integration has no permission for other countries.
Base URL: https://ris.api.bmw.com/m2m/sales/masterdata
Authentication — OAuth2 Client Credentials
Token URL: POST https://auth.bmwgroup.net/auth/oauth2/realms/root/realms/machine2machine/access_token
| Header | Value |
|---|---|
Authorization | Basic {base64(client_id:client_secret)} |
Content-Type | application/x-www-form-urlencoded |
Body (form-encoded string, NOT JSON):
grant_type=client_credentials&scope=machine2machine&client_id={client_id}
Scope must be machine2machine (not openid). Token is a Bearer JWT used in
Authorization: Bearer {token} on all RIS requests.
Additional headers for RIS requests:
| Header | Value |
|---|---|
apikey | {BMW_RIS_API_KEY} |
bmw-ris-conversation-id | ce470bc2-bd25-41f0-8952-821d7de46675 |
bmw-ris-system-id | 30850 |
These are fixed IDs from the BMW RIS web client.
Standard query params (shared across all RIS endpoints)
| Param | Value |
|---|---|
source | datafox |
brand | bmwCar or bmwi |
country | ISO-2 lowercase, e.g. in |
orderDate | today's date |
effectDate | today + 30 days |
5a. Model IDs
GET /vehicle-configurations/v1/models
Response: {modelResponse: {key: {agModelCode: "...", ...}}}. Extract
agModelCode values. Two brand calls per locale (bmwCar and bmwi).
5b. Model Feature Endpoints (per model)
Four endpoint families, one request per (brand, model_id):
| Endpoint | URL |
|---|---|
| Options | GET /vehicle-configurations/v1/models/{model_id}/options |
| Packages | GET /vehicle-configurations/v1/models/{model_id}/packages |
| Phrases | GET /vehicle-configurations/v1/models/{model_id}/options/phrases (+ Accept-Language: {language}-{COUNTRY} header) |
| Prices | GET /pricings/v1/price-list (with modelCode={model_id}, priceListsIdentifiers=datafox, currency=EUR) |
404 is suppressed on all four. Accept-Language format: en-IN (BCP47).
Availability note: Token acquisition confirmed successful in ECS (confirmed 2026-06-20).
API returns 403 — credentials authenticate but are not authorized for this endpoint.
Correct credentials are in GCP Secret Manager: ris-auth-credential, ris-api-key,
ris-client-id. These must be provisioned in ECS container env before the endpoint
becomes callable.
6. BMW SA BFF — South Africa Inventory
BMW South Africa uses an Angular SPA backed by a Rockar/Magento BFF at
buy.bmw.co.za. The BFF proxies to a DSP GraphQL backend. No credentials required
— auth uses an anonymous JWT acquired in Step 1.
Base URL: https://buy.bmw.co.za
Step 1 — Acquire Anonymous JWT
POST /api/load-page/bmw
Headers:
| Header | Value |
|---|---|
User-Agent | (browser UA) |
Accept | application/json, text/plain, */* |
Content-Type | application/json |
Origin | https://buy.bmw.co.za |
Referer | https://buy.bmw.co.za/new-cars |
Response: {token: "..."} — a JWT string.
Step 2 — Inventory Products
POST /api/product/products
Add clienttoken: {token} header from Step 1.
Request body:
{
"handle": "bto",
"storefrontCode": "bmw_vehicle",
"first": 500,
"after": 0,
"productCatalogFilters": [{"code": "", "values": []}],
"productCatalogSorting": {"method": "monthlyPrice", "order": "ASC"},
"productCatalogFinanceFilters": {
"financeType": ["select", "instalment"],
"minMonthlyBudget": 0,
"maxMonthlyBudget": 50000000
}
}
handle=bto selects the build-to-order (new-cars) category. first=500 returns
all vehicles in one request (~84 vehicles as of 2026-06-20). after=0 is the
cursor start.
Response fields: id, vin, model, title, price, bodyType, fuelType,
driveTrain, modelYear, manufacturerCode, images.
Observed volume: 84 vehicles (totalCount=84). No pagination needed at current scale.