Authentication overview

Transport for Germany secures access to its comprehensive suite of public transport data APIs through an API key authentication model. This method requires developers to obtain a unique key from the official developer portal, which is then passed with each API request to verify the client's identity and authorize access to data and services, such as real-time GTFS-RT, historical GTFS, and route planning APIs.

The API key serves as the primary credential for all interactions with the Transport for Germany API endpoints, ensuring that only authorized applications can consume the data. This approach simplifies the authentication process for developers while maintaining a robust security posture for the data providers.

Proper management and protection of API keys are critical to prevent unauthorized access to your account and to safeguard the integrity of the services you build using Transport for Germany's data. Adherence to security best practices, such as storing keys securely and rotating them periodically, is strongly recommended.

Supported authentication methods

Transport for Germany primarily utilizes API key authentication for its API endpoints. This method involves a secret token that clients include in their API requests.

API keys are generally suitable for identifying client applications rather than individual users, providing a straightforward way to control and monitor API access. While effective for rate limiting and basic usage tracking, developers should implement additional security measures on the client side, especially for public-facing applications.

Transport for Germany's API key mechanism simplifies client authentication, and its usage is detailed in the Transport for Germany documentation portal.

Method When to use Security Level
API Key Server-to-server communication, backend applications, mobile app backends. Moderate (requires careful key management to prevent exposure).

Getting your credentials

To access Transport for Germany's APIs, you must first obtain an API key. This process is initiated through the official developer portal.

  1. Register for a Developer Account: Navigate to the Transport for Germany homepage and register for a new developer account. This typically involves providing an email address and creating a password.
  2. Access the Developer Dashboard: Once registered and logged in, you will be redirected to your developer dashboard. This dashboard is your central hub for managing API keys, monitoring usage, and accessing documentation.
  3. Generate an API Key: Within the dashboard, locate the section for API Keys or Credentials. You will find an option to generate a new API key. Follow the prompts, which may include naming your key for organizational purposes.
  4. Copy Your API Key: After generation, your unique API key will be displayed. It is crucial to copy this key immediately and store it securely, as it may not be retrievable again for security reasons. If lost, you typically must generate a new key.
  5. Understand Usage Limits: Be aware of the usage limits associated with your chosen plan, starting with the Developer Plan's 5,000 requests per month, as detailed on the Transport for Germany pricing page. Exceeding these limits may require upgrading your plan or could result in temporary service interruption.

For detailed, step-by-step instructions, refer to the Transport for Germany API reference documentation.

Authenticated request example

Once you have obtained your API key, you can use it to make authenticated requests to the Transport for Germany API endpoints. The API key should be included in the header of your HTTP requests. The specific header name is X-API-Key.

Below are examples of how to make an authenticated request using common programming languages supported by Transport for Germany's SDKs: Python, JavaScript, and Go.

Python example


import requests
import os

API_KEY = os.environ.get("TRANSPORT_FOR_GERMANY_API_KEY")
BASE_URL = "https://api.transportfor.germany/v1"

def get_realtime_data(stop_id):
    headers = {
        "X-API-Key": API_KEY,
        "Accept": "application/json"
    }
    endpoint = f"{BASE_URL}/realtime/stops/{stop_id}"
    try:
        response = requests.get(endpoint, headers=headers)
        response.raise_for_status()  # Raise an HTTPError for bad responses (4xx or 5xx)
        return response.json()
    except requests.exceptions.HTTPError as err:
        print(f"HTTP error occurred: {err} - {response.text}")
    except requests.exceptions.ConnectionError as err:
        print(f"Error Connecting: {err}")
    except requests.exceptions.Timeout as err:
        print(f"Timeout Error: {err}")
    except requests.exceptions.RequestException as err:
        print(f"An unexpected error occurred: {err}")
    return None

# Example usage
# Ensure TRANSPORT_FOR_GERMANY_API_KEY environment variable is set
# For example: export TRANSPORT_FOR_GERMANY_API_KEY="your_api_key_here"
if __name__ == "__main__":
    data = get_realtime_data("8000105") # Example stop ID for Berlin Hbf
    if data:
        print(data)

JavaScript (Node.js with fetch) example


const fetch = require('node-fetch');

const API_KEY = process.env.TRANSPORT_FOR_GERMANY_API_KEY;
const BASE_URL = "https://api.transportfor.germany/v1";

async function getRealtimeData(stopId) {
    if (!API_KEY) {
        console.error("Error: TRANSPORT_FOR_GERMANY_API_KEY environment variable is not set.");
        return;
    }

    const headers = {
        "X-API-Key": API_KEY,
        "Accept": "application/json"
    };
    const endpoint = `${BASE_URL}/realtime/stops/${stopId}`;

    try {
        const response = await fetch(endpoint, {
            method: 'GET',
            headers: headers
        });

        if (!response.ok) {
            const errorBody = await response.text();
            throw new Error(`HTTP error! Status: ${response.status}, Body: ${errorBody}`);
        }

        const data = await response.json();
        return data;
    } catch (error) {
        console.error("Failed to fetch real-time data:", error);
    }
}

// Example usage
// Ensure TRANSPORT_FOR_GERMANY_API_KEY environment variable is set
// For example: export TRANSPORT_FOR_GERMANY_API_KEY="your_api_key_here"
(async () => {
    const data = await getRealtimeData("8000105"); // Example stop ID for Berlin Hbf
    if (data) {
        console.log(data);
    }
})();

Go example


package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	baseURL = "https://api.transportfor.germany/v1"
)

type StopData struct {
	// Define your struct based on the expected JSON response from the API
	// For simplicity, using map[string]interface{} here
	// In a real application, define proper structs for strong typing.
	Data map[string]interface{}
}

func getRealtimeData(stopID string) (*StopData, error) {
	apiKey := os.Getenv("TRANSPORT_FOR_GERMANY_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("TRANSPORT_FOR_GERMANY_API_KEY environment variable not set")
	}

	client := &http.Client{}
	req, err := http.NewRequest("GET", fmt.Sprintf("%s/realtime/stops/%s", baseURL, stopID), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %w", err)
	}

	req.Header.Add("X-API-Key", apiKey)
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error making request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		bodyBytes, _ := ioutil.ReadAll(resp.Body)
		return nil, fmt.Errorf("API returned non-OK status: %d, body: %s", resp.StatusCode, string(bodyBytes))
	}

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("error reading response body: %w", err)
	}


	var stopData StopData
	err = json.Unmarshal(bodyBytes, &stopData.Data)
	if err != nil {
		return nil, fmt.Errorf("error unmarshalling response: %w", err)
	}

	return &stopData, nil
}

func main() {
	// Example usage
	// Ensure TRANSPORT_FOR_GERMANY_API_KEY environment variable is set
	// For example: export TRANSPORT_FOR_GERMANY_API_KEY="your_api_key_here"
	stopData, err := getRealtimeData("8000105") // Example stop ID for Berlin Hbf
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	jsonOutput, err := json.MarshalIndent(stopData.Data, "", "  ")
	if err != nil {
		fmt.Println("Error marshalling JSON:", err)
		return
	}
	fmt.Println(string(jsonOutput))
}

Security best practices

Protecting your API keys is essential to maintain the security and integrity of your applications and to prevent unauthorized access to Transport for Germany's services. Adhere to the following best practices:

  • Do not embed API keys directly in source code: Hardcoding keys makes them vulnerable to exposure if your code repository becomes compromised. Instead, use environment variables, configuration files, or secret management services. This is a common practice recommended by major cloud providers like Google Cloud's API key best practices.
  • Use environment variables for server-side applications: For backend services, store your API key as an environment variable. This allows you to inject the key at runtime without it ever being part of the codebase.
  • Utilize secret management services: For more complex deployments or production environments, consider using dedicated secret management solutions such as AWS Secrets Manager, Azure Key Vault, or Google Secret Manager. These services provide secure storage, retrieval, and rotation of sensitive credentials.
  • Restrict API key privileges: If Transport for Germany introduces granular permissions for API keys in the future, always assign the minimum necessary permissions to each key. This principle of least privilege limits the potential damage if a key is compromised.
  • Implement IP whitelisting (if available): If Transport for Germany's API gateway supports IP whitelisting, configure your API key to only accept requests originating from a list of approved IP addresses. This adds an extra layer of security, ensuring that even if a key is stolen, it cannot be used from unauthorized locations.
  • Rotate API keys regularly: Periodically generate new API keys and revoke old ones. This practice minimizes the window of opportunity for a compromised key to be exploited.
  • Monitor API key usage: Regularly review your API usage metrics and logs in the Transport for Germany developer dashboard. Unusual spikes in activity or requests from unexpected locations can indicate a compromised key. The Google Maps API security best practices also recommend monitoring.
  • Secure client-side applications: For browser-based or mobile applications, directly embedding API keys is inherently risky. Implement a backend proxy or serverless function to make API calls on behalf of the client, protecting the key from exposure in the client application.
  • Avoid exposing keys in URLs: Never pass API keys as query parameters in URLs, as they can be logged in server logs, browser history, and proxy caches. Always use request headers for API key transmission.
  • Implement rate limiting and quotas: While Transport for Germany enforces its own rate limits, consider implementing client-side rate limiting to prevent accidental overuse or to mitigate the impact of a compromised key making excessive requests before it can be revoked.