BYTETOOLS

MVG (Munich) API

Free Munich public transport departures API with no key: live U-Bahn, S-Bahn, tram and bus times with delays, platforms and occupancy. Tested example and live response.

No API key requiredCORS enabledHTTPSFree tier

Endpoint tested and returned HTTP 200 on 2026-08-21

What is the MVG (Munich) API?

The MVG departures API is the endpoint Munich's transport operator uses for its own apps, and it works without a key. It returns live departures for any stop with planned and real-time times, delay in minutes, platform, destination, cancellation flag and an occupancy estimate.

Munich's stop identifiers follow the German DIVA convention — `de:09162:6` is Marienplatz — and once you have one the departures endpoint is a single GET. The `occupancy` field is the unusual one: MVG publishes a coarse crowding estimate as `LOW`, `MEDIUM`, `HIGH` or `UNKNOWN`, which few operators expose at all and which is genuinely useful for anyone choosing between two imminent trains.

Times come as Unix milliseconds, and there are two of them per departure: `plannedDepartureTime` and `realtimeDepartureTime`. `delayInMinutes` is the signed difference and can be negative when a service is running early, which happens more than you would expect on tram routes. The `realtime` boolean says whether the figure is a live measurement or a fallback to the timetable — a false there means the delay is zero because nothing is known, not because the service is on time.

Quick facts

Base URL
https://www.mvg.de/api/bgw-pt/v3
Authentication
No API key or account. It is MVG's own public endpoint, used by its website and apps, and is not formally documented for third-party use.
Rate limit
No published quota. Departure predictions change every few seconds; polling every 20 to 30 seconds is ample.
Pricing
Free.
CORS
Enabled — callable directly from browser JavaScript
Official docs
Read the docs

How to use the MVG (Munich) API

Every request below was executed against the live API on 2026-08-21, and the response shown is the real body it returned — not an illustration.

1. Fetch live departures for a Munich stop

GET https://www.mvg.de/api/bgw-pt/v3/departures?globalId=de:09162:6&limit=3

curl
curl 'https://www.mvg.de/api/bgw-pt/v3/departures?globalId=de:09162:6&limit=3'
JavaScript (fetch)
const res = await fetch("https://www.mvg.de/api/bgw-pt/v3/departures?globalId=de:09162:6&limit=3");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

res = requests.get("https://www.mvg.de/api/bgw-pt/v3/departures?globalId=de:09162:6&limit=3", timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
[
  {
    "plannedDepartureTime": 1787299260000,
    "realtime": false,
    "realtimeDepartureTime": 1787299260000,
    "transportType": "UBAHN",
    "label": "U5",
    "divaId": "010U5",
    "network": "swm",
    "trainType": "",
    "destination": "Laimer Platz",
    "cancelled": false,
    "sev": false,
    "platform": 1,
    "platformChanged": false,
    "messages": [],
    "infos": [],
    "bannerHash": "",
    "occupancy": "LOW",
    "stationGlobalId": "de:09162:6",
    "stopPointGlobalId": "de:09162:6:55:55",
    "lineId": "swm:010U5:G:R:016",
    "tripCode": 925
  },
  {
    "plannedDepartureTime": 1787299260000,
    "realtime": false,
    "realtimeDepartureTime": 1787299260000,
    "transportType": "UBAHN",
    "label": "U4",
    "divaId": "010U4",
    "network": "swm",
    "trainType": "",
    "destination": "Arabellapark",
    "cancelled": false,
    "sev": false,
    "platform": 2,
    "platformChanged": false,
    "messages": [],
    "infos": [],
    "bannerHash": "",
    "occupancy": "UNKNOWN",
    "stationGlobalId": "de:09162:6",
    "stopPointGlobalId": "de:09162:6:55:56",
    "lineId": "swm:010U4:G:H:016",
    "tripCode": 18
  },
  {
    "plannedDepartureTime": 1787299260000,
    "realtime": true,
    "delayInMinutes": 1,
    "realtimeDepartureTime": 1787299320000,
    "transportType": "TRAM",
    "label": "17",
    "divaId": "02017",
    "network": "swm",
    "trainType": "",
    "destination": "St. Emmeram",
    "cancelled": false,
    "sev": false,
    "messages": [],
    "infos": [],
    "bannerHash": "",
    "occupancy": "UNKNOWN",
    "stationGlobalId

Parameters

ParameterTypeRequiredDescription
globalIdqueryRequiredDIVA stop identifier in the form `de:09162:6`. Marienplatz is 6. de:09162:6
limitqueryOptionalMaximum departures to return. 3
offsetInMinutesqueryOptionalSkip departures sooner than this, useful when you need walking time to the stop. 5
transportTypesqueryOptionalRestrict modes: `UBAHN`, `SBAHN`, `TRAM`, `BUS`, `REGIONAL_BUS`, `BAHN`. UBAHN,TRAM
(location search)pathOptional`/locations?query=` resolves a stop name to its `globalId`.

Response fields

plannedDepartureTimeinteger
Timetabled departure as Unix milliseconds — milliseconds, not seconds.
realtimeDepartureTimeinteger
Live expected departure, same units. This is the figure to display.
delayInMinutesinteger
Signed delay. Negative means early, which does happen.
realtimeboolean
Whether live data backed this prediction. False means the times are timetable fallbacks.
transportTypestring
`UBAHN`, `SBAHN`, `TRAM`, `BUS`, `REGIONAL_BUS` or `BAHN`.
labelstring
Line label as shown on the vehicle — "U5", "19", "X30".
destinationstring
Headsign destination for this departure.
platform / platformChangedinteger / boolean
Platform number and whether it differs from the planned one. Check the flag before trusting signage.
cancelled / sevboolean
Whether the departure is cancelled, and whether it is a replacement bus service (Schienenersatzverkehr).
occupancystring
Crowding estimate: `LOW`, `MEDIUM`, `HIGH` or `UNKNOWN`.
messages / infosarray
Disruption notices attached to this departure, usually in German.

What you can build with the MVG (Munich) API

  • Build a Munich departure board for a stop or an office lobby
  • Show the next trains home with walking time already deducted
  • Warn commuters about cancellations and platform changes
  • Choose between two imminent services using the occupancy estimate
  • Filter departures to a single mode such as U-Bahn only

Common errors and how to fix them

Dates land in 1970

Times are Unix milliseconds, not seconds.

Fix: Divide by 1000 for libraries that expect seconds. This is the most frequent mistake with this API.

Empty array for a valid stop

`offsetInMinutes` excluded everything, or nothing is running.

Fix: Drop the offset and retry. Munich's network is quiet between roughly 01:00 and 04:00, when an empty board is correct.

delayInMinutes is 0 but the train is late

`realtime` is false, so the times are timetable fallbacks.

Fix: Show live figures only when `realtime` is true, and label the rest as scheduled.

Notices are unreadable

`messages` and `infos` are in German only.

Fix: Display them as-is with a language note, or filter to the structured `cancelled` and `platformChanged` flags for logic.

MVG (Munich) API — frequently asked questions

Is the MVG API free?

Yes, free with no key or account. It is the operator's own public endpoint, used by its website and apps, though it is not formally documented for third-party use and could change without warning.

How do I find a stop id?

Use the `/locations?query=` endpoint with a stop name. Ids follow the German DIVA format, `de:09162:6`, where 09162 identifies Munich and the final segment identifies the stop.

What does the occupancy field mean?

It is a coarse crowding estimate — LOW, MEDIUM, HIGH or UNKNOWN — for the approaching service. Few operators publish this at all, and it is genuinely useful when two trains are due within a couple of minutes of each other.

Does it cover S-Bahn as well as U-Bahn?

Yes. Departures cover U-Bahn, S-Bahn, tram, city and regional buses, and regional trains, filterable through `transportTypes`. S-Bahn services are operated by Deutsche Bahn but appear in the MVG board.

Tools that pair with this API

MVG (Munich) is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 2026-08-21; always check the official documentation before relying on this API in production, as terms and limits can change.