Skip to content

Latest commit

 

History

History
160 lines (121 loc) · 6.4 KB

hafas-mgate-api.md

File metadata and controls

160 lines (121 loc) · 6.4 KB

HAFAS mgate.exe protocol

The protocol of mgate.exe HAFAS endpoints is not openly (and freely) documented. The following documentation is based on general observations and reverse-engineering.

Note: There are also rest.exe (a.k.a. "open API", a.k.a. "REST API") endpoints. This documentation is not about them.

date & time format

Dates are encoded as YYYYMMDD, time strings as HHMMSS. These are in the timezone configured on the HAFAS/server side, per endpoint.

Whenever HAFAS returns a time string that exceeds the day the response describes, it will add a "day offset". As an example, when you query departures at 2019-12-12T23:50+01:00 for the next 30 minutes, it will encode the departure at 2019-12-13T00:13+01:00 as 20191212 & 01001300.

For working code, check out parseDateTime().

coordinate format

All endpoints I've seen so far use WGS84. Values are multiplied by 10^6 though, so you would encode {latitude: 1.23, longitude: -2.34} as {Y: 1230000: X: -2340000}. There's an optional parameter z with the elevation.

For working code, check out formatAddress().

querying the API

In many aspects, the API looks and feels like RPCs. You must send queries via HTTP POST, with the minimal JSON body looking like this:

{
	"auth": {
		"type": "AID",
		"aid": "…" // endpoint-specific authentication token, e.g. `1Rxs112shyHLatUX4fofnmdxK`
	},
	"ver": "…", // endpoint-specific string, e.g. `1.15`
	"ext": "…", // endpoint-specific string, e.g. `BVG.1`
	"client": {
		"type": "IPA", // might also be `IPH` for "iPhone" or `WEB` for "web client"
		"id": "…", // endpoint-specific string, e.g. `BVG`
		"name": "…", // endpoint-specific string, e.g. `FahrInfo`
		"v": "…" // endpoint-specific string, e.g. `4070700`
	},
	"lang": "…", // language, sometimes 2-digit (e.g. `de`), sometimes 3-digit (e.g. `deu`)
	"svcReqL": [
		{
			"meth": "…", // name of the API call, supported values depend on the endpoint
			"req": {
				// actual request parameters…
			}
			// some endpoints also require this:
			"cfg": {
				"cfgGrpL": [],
				"cfgHash": "…" // endpoint-specific string
			}
		}
	]
}
  • The data in client must be correct, otherwise HAFAS will reject your request.
  • HAFAS will return slightly different response formats (and slightly different levels of detail) for different ver, ext and client.v values.
  • All endpoints known support JSON & UTF-8, so make sure to send Accept: application/json & Accept-Charset: utf-8 headers.
  • Most endpoints support at least GZIP compression, so make sure to send a Accept-Encoding: gzip header.

For working code, check out request().

Authentication

There are three known types of authentication used among mgate.exe endpoints.

For working code, check out hafas-client's request(), public-transport-enabler's Java implementation, TripKit's Swift implementation or marudor.de's TypeScript implementation.

unprotected endpoints

You can just query these, as long as you send a formally correct request.

endpoints using the checksum query parameter

checksum is a message authentication code: You can compute it by hashing the request body and a secret salt.

This secret can be read from the config file inside the accompanying client app. There is no guide for this yet, so please open an issue.

endpoints using the mic & mac query parameters

mic is a message integrity code, the hash of the request body.

mac is a message authentication code, the hash of mic and a secret salt.

This secret can be read from the config file inside the accompanying client app. There is no guide for this yet, so please open an issue.

API responses

A minimal valid response looks like this:

{
	"ver": "…", // endpoint-specific string, e.g. `1.15`
	"lang": "…", // language
	"ext": "…", // endpoint-specific string, e.g. `BVG.1`
	"id": "…", // unique ID for each response?
	"svcResL": [
		{
			"meth": "StationBoard",
			"err": "OK",
			"res": {
				// result of the API call
			}
		}
	]
}

For working code, check out request().

parse error

todo: generic server error

{
	"ver": "…", // endpoint-specific string, e.g. `1.15`
	"lang": "…", // language, sometimes 2-digit (e.g. `de`), sometimes 3-digit (e.g. `deu`)
	"err": "PARSE", // error code
	"errTxt": "…", // error message, not always present
	"svcResL": []
}

authentication error

{
	"ver": "…", // endpoint-specific string, e.g. `1.15`
	"lang": "…", // language
	"ext": "…", // endpoint-specific string, e.g. `BVG.1`
	"err": "AUTH", // error code
	"errTxt": "…", // error message, not always present
	"svcResL": []
}

API-call-specific error

{
	"ver": "…", // endpoint-specific string, e.g. `1.15`
	"lang": "…", // language
	"ext": "…", // endpoint-specific string, e.g. `BVG.1`
	"svcResL": [
		{
			"meth": "StationBoard",
			"err": "…", // error code, e.g. `H9300`
			"errTxt": "…", // error message, e.g. `Unknown arrival station`
			"res": {}
		}
	]
}

more ressources