Sign inTry it

Plan a trip on Munich public transport (U-Bahn, S-Bahn, tram, bus).

Finds connections between two stops in Munich's network (MVV area) like the MVG journey planner: departure and arrival times, duration, number of changes, and each leg with line, direction, platform and stop names. Depart at or arrive by a given time; choose transport types.

No reports yetRead-only, no login
Site
MVG (Munich public transport), Germany
Version
v1
Runs, last 7 days
No reports yet
sha256
098239050958…

Run it with your agent

after installing Wield

Ask in plain words. Your agent finds this recipe and calls it:

“Plan a trip on Munich public transport (U-Bahn, S-Bahn, tram, bus).”

Read-only: it changes nothing on the site. No login needed.

{
  "tool": "run",
  "arguments": {
    "recipe_id": "mvg.de/search-connections",
    "params": {
      "datetime": "2026-11-09T09:00:00+01:00",
      "from": "Marienplatz",
      "to": "Garching Forschungszentrum"
    }
  }
}

Requests

sent from your browser, in order
  1. 1GET/api/bgw-pt/v3/locations?queryMVG's stop search (the journey planner's autocomplete).
  2. 2GET/api/bgw-pt/v3/locations?query
  3. 3GET/api/bgw-pt/v3/routes?destinationStationGlobalId&originStationGlobalId&routingDateTime&routingDateTimeIsArrival&transportTypesMVG's routing API, the journey planner's own call.

Parameters

from your agent
arrive_bybooleandatetime is the latest arrival instead of the earliest departure = false
datetimestringrequiredWhen, with UTC offset: Munich is +01:00 in winter, +02:00 in summer, e.g. '2026-11-09T09:00:00+01:00'
fromstringrequiredStart stop, e.g. 'Marienplatz', 'Hauptbahnhof', 'Garching'
tostringrequiredDestination stop
transport_typesstring[] = ["UBAHN","SBAHN","TRAM","BUS","REGIONAL_BUS","BAHN","SCHIFF","RUFTAXI"]

Returns

to your agent
connectionsobject[]arrival, changes, departure, duration_min, legs
fromstring
tostring

Where it can send

  • www.mvg.de

Anything else is blocked by the extension.

Reads from your session

Nothing. Your browser attaches the site's cookies by itself.

Used only in requests to the addresses on the left. Never sent to wield.run or your agent.

Checks

a run passes when
  • length(output.connections) > `1`
  • output.connections[0].duration_min > `0`
  • length(output.connections[0].legs) > `0`
  • output.connections[0].legs[0].line != `null`
  • starts_with(output.connections[0].departure, '2026-11-09T')

Raw recipe

Served as canonical JSON from /api/v1/recipes/mvg.de/search-connections, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/mvg.de/search-connections | shasum -a 256
# 098239050958b57f6a8b40dc8763e5a971097245f53eacc8510b1e7f4bf26c45
mvg.de/search-connections.json, v1
{
  "description": "Finds connections between two stops in Munich's network (MVV area) like the MVG journey planner: departure and arrival times, duration, number of changes, and each leg with line, direction, platform and stop names. Depart at or arrive by a given time; choose transport types.",
  "effect": "read",
  "id": "mvg.de/search-connections",
  "keywords": [
    "mvg",
    "mvv",
    "münchen",
    "munich",
    "u-bahn",
    "s-bahn",
    "tram",
    "bus",
    "verbindung",
    "fahrplan",
    "öpnv",
    "public transport",
    "journey planner",
    "train",
    "route"
  ],
  "output": {
    "schema": {
      "properties": {
        "connections": {
          "items": {
            "properties": {
              "arrival": {
                "type": "string"
              },
              "changes": {
                "type": "integer"
              },
              "departure": {
                "type": "string"
              },
              "duration_min": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "legs": {
                "items": {
                  "properties": {
                    "arrival": {
                      "type": "string"
                    },
                    "departure": {
                      "type": "string"
                    },
                    "direction": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "from": {
                      "type": "string"
                    },
                    "from_platform": {
                      "type": [
                        "integer",
                        "string",
                        "null"
                      ]
                    },
                    "line": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "notices": {
                      "type": "integer"
                    },
                    "to": {
                      "type": "string"
                    },
                    "type": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "type": "object"
                },
                "type": "array"
              }
            },
            "type": "object"
          },
          "type": "array"
        },
        "from": {
          "type": "string"
        },
        "to": {
          "type": "string"
        }
      },
      "type": "object"
    },
    "value": "{from: join(', ', [steps.origin.name, steps.origin.place]), to: join(', ', [steps.destination.name, steps.destination.place]), connections: map(&(let $p = parts, $dep = parts[0].from.plannedDeparture, $arr = parts[-1].to.plannedDeparture in {departure: $dep, arrival: $arr, duration_min: let $m = (to_number(trim_left($arr[11:13], '0')) || `0`) * `60` + (to_number(trim_left($arr[14:16], '0')) || `0`) - (to_number(trim_left($dep[11:13], '0')) || `0`) * `60` - (to_number(trim_left($dep[14:16], '0')) || `0`) in (($m < `0` && $m + `1440`) || $m), changes: length($p[?line.transportType != 'PEDESTRIAN']) - `1`, legs: map(&{line: line.label || `null`, type: line.transportType || `null`, direction: line.destination || `null`, from: from.name, from_platform: from.platform || `null`, departure: from.plannedDeparture, to: to.name, arrival: to.plannedDeparture, notices: length(messages || `[]`)}, $p)}), steps.routes.routes || `[]`)}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "arrive_by": {
        "default": false,
        "description": "datetime is the latest arrival instead of the earliest departure",
        "type": "boolean"
      },
      "datetime": {
        "description": "When, with UTC offset: Munich is +01:00 in winter, +02:00 in summer, e.g. '2026-11-09T09:00:00+01:00'",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2})?[+-]\\d{2}:\\d{2}$",
        "type": "string"
      },
      "from": {
        "description": "Start stop, e.g. 'Marienplatz', 'Hauptbahnhof', 'Garching'",
        "maxLength": 80,
        "minLength": 2,
        "type": "string"
      },
      "to": {
        "description": "Destination stop",
        "maxLength": 80,
        "minLength": 2,
        "type": "string"
      },
      "transport_types": {
        "default": [
          "UBAHN",
          "SBAHN",
          "TRAM",
          "BUS",
          "REGIONAL_BUS",
          "BAHN",
          "SCHIFF",
          "RUFTAXI"
        ],
        "items": {
          "enum": [
            "UBAHN",
            "SBAHN",
            "TRAM",
            "BUS",
            "REGIONAL_BUS",
            "BAHN",
            "SCHIFF",
            "RUFTAXI"
          ],
          "type": "string"
        },
        "minItems": 1,
        "type": "array"
      }
    },
    "required": [
      "from",
      "to",
      "datetime"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "browser-inspect",
    "notes": "MVG's journey planner calls www.mvg.de/api/bgw-pt/v3/locations?query= (stops: type STATION, globalId like de:09162:2) and /api/bgw-pt/v3/routes?originStationGlobalId&destinationStationGlobalId&routingDateTime&routingDateTimeIsArrival&transportTypes. routingDateTime needs an explicit offset (an offset-less time gets HTTP 400). Times in the answer are local ISO with offset; durations are computed from them. Public JSON, answers servers; robots.txt allows everything.",
    "recorded_at": "2026-11-07T19:04:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "DE",
    "id": "mvg.de",
    "language": "de",
    "name": "MVG (Munich public transport)",
    "origin": "https://www.mvg.de",
    "origins": [
      "https://www.mvg.de"
    ]
  },
  "steps": [
    {
      "description": "MVG's stop search (the journey planner's autocomplete).",
      "expect": {
        "assert": "length(body[?type == 'STATION']) > `0`",
        "content_type": "json",
        "status": [
          200
        ]
      },
      "extract": {
        "json": {
          "id": "[?type == 'STATION'] | [0].globalId",
          "name": "[?type == 'STATION'] | [0].name",
          "place": "[?type == 'STATION'] | [0].place"
        }
      },
      "id": "origin",
      "request": {
        "headers": {
          "Accept": "application/json"
        },
        "method": "GET",
        "query": {
          "query": "{{params.from}}"
        },
        "url": "/api/bgw-pt/v3/locations"
      }
    },
    {
      "expect": {
        "assert": "length(body[?type == 'STATION']) > `0`",
        "content_type": "json",
        "status": [
          200
        ]
      },
      "extract": {
        "json": {
          "id": "[?type == 'STATION'] | [0].globalId",
          "name": "[?type == 'STATION'] | [0].name",
          "place": "[?type == 'STATION'] | [0].place"
        }
      },
      "id": "destination",
      "request": {
        "headers": {
          "Accept": "application/json"
        },
        "method": "GET",
        "query": {
          "query": "{{params.to}}"
        },
        "url": "/api/bgw-pt/v3/locations"
      }
    },
    {
      "description": "MVG's routing API, the journey planner's own call.",
      "expect": {
        "content_type": "json",
        "status": [
          200
        ]
      },
      "extract": {
        "json": {
          "routes": "@"
        }
      },
      "id": "routes",
      "request": {
        "headers": {
          "Accept": "application/json"
        },
        "method": "GET",
        "query": {
          "destinationStationGlobalId": "{{steps.destination.id}}",
          "originStationGlobalId": "{{steps.origin.id}}",
          "routingDateTime": "{{params.datetime}}",
          "routingDateTimeIsArrival": "{{params.arrive_by | string}}",
          "transportTypes": "{{params.transport_types | join:,}}"
        },
        "url": "/api/bgw-pt/v3/routes"
      }
    }
  ],
  "task": "Plan a trip on Munich public transport (U-Bahn, S-Bahn, tram, bus)",
  "tos": {
    "notes": "Three small requests per run (two stop lookups, one routing call), the same ones the MVG website makes.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "length(output.connections) > `1`",
      "output.connections[0].duration_min > `0`",
      "length(output.connections[0].legs) > `0`",
      "output.connections[0].legs[0].line != `null`",
      "starts_with(output.connections[0].departure, '2026-11-09T')"
    ],
    "example_params": {
      "datetime": "2026-11-09T09:00:00+01:00",
      "from": "Marienplatz",
      "to": "Garching Forschungszentrum"
    },
    "max_ms": 4000
  },
  "version": 1
}