Developer
Menü

Zugläufe

Ein Zug über viele Tage: wann er wo war, wie spät, auf welchem Gleis, was ausfiel und mit welchem Triebzug er fuhr. Vergangene Tage aus unserem Zugarchiv, heute und die nächsten Tage aus der Auskunft. Dazu die Pünktlichkeit eines Zuges und eine Suche über alle Züge eines Tages.

Objekte

Objekt Zuglauf

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Tag der Abfahrt am ersten Halt)
trainobject{ name, category, number }, z. B. ICE 611
operator?stringBetreiber
origin?object{ id, name }
destination?object{ id, name }
departure?stringGeplante Abfahrt am ersten Halt
arrival?stringGeplante Ankunft am letzten Halt
arrival_delay?integerVerspätung am Ziel in Minuten
max_delay?integerGrößte Verspätung unterwegs
cancelledstringno, partial (Halte fielen aus) oder full
formation?object[]Wagenreihung je Zugteil { trainset, series, series_name, vehicles, train, diagram_url }: Triebzug, Baureihe und ihr Name (z. B. ICE 4), Zahl der Wagen, Zug dieses Teils (bei vereinigten Zügen wie ICE 844 und ICE 854 je Teil ein anderer), Plan der Baureihe
completebooleantrue, wenn der Zug angekommen ist und der Tag fertig aufgezeichnet
sourcestringNur beim einzelnen Lauf: archive, live (heute, aus der Auskunft) oder plan (künftiger Tag)
stopsinteger | object[]In Listen die Zahl der Halte, beim einzelnen Lauf jeder Halt: { station, arrival, departure, platform, cancelled, additional, reasons }; reasons sind die Gründe der DB { code, text, type, time } an dem Halt, wo sie gemeldet wurden; Zeiten { scheduled, actual, delay }, Gleis { scheduled, actual, changed }
{
  "date": "2026-10-16",
  "train": {
    "name": "ICE 611",
    "category": "ICE",
    "number": "611"
  },
  "operator": "DB Fernverkehr AG",
  "origin": {
    "id": "8002553",
    "name": "Hamburg-Altona"
  },
  "destination": {
    "id": "8000261",
    "name": "München Hbf"
  },
  "departure": "2026-10-16T11:26:00+02:00",
  "arrival": "2026-10-16T20:32:00+02:00",
  "arrival_delay": 7,
  "max_delay": 12,
  "cancelled": "no",
  "stops": 18,
  "formation": [
    {
      "trainset": "9462",
      "series": "412.13",
      "series_name": "ICE 4",
      "vehicles": 13,
      "diagram_url": "https://bahnhoftafel.de/fahrzeuge/plaene/412.13.pdf"
    }
  ],
  "complete": true
}

Tage eines Zuges

GET/v1/trains/{train}/runsEimer standard

Alle aufgezeichneten Tage eines Zuges mit Verspätung am Ziel, größter Verspätung, Ausfällen und Triebzug, dazu die Pünktlichkeit im Zeitraum. Wie die Übersicht bei zugfinder.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
fromstringAb diesem Tag, Standard: vor 30 Tagen
tostringBis zu diesem Tag, Standard: heute
limitintegerHöchstens so viele TageStandard: 601 bis 400

Antwort

Objekt { train, summary, runs: Zuglauf[] }; summary: { runs, on_time_share, average_arrival_delay, max_delay, cancelled_full, cancelled_partial }. Pünktlich heißt wie bei der DB: weniger als 6 Minuten Verspätung am Ziel.

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/runs" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/runs", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/runs",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Zuglauf an einem Tag

GET/v1/trains/{train}/runs/{date}Eimer standard, 2 Marken

Jeder Halt eines Zuges an einem Tag mit Plan, tatsächlicher Zeit, Verspätung, Gleis und Ausfällen, dazu die Wagenreihung. Vergangene Tage kommen aus dem Archiv, heute live, künftige Tage als Plan (einige Wochen voraus).

Info

Aufgezeichnet wird der Fernverkehr (ICE, IC, EC, Nightjet, Flixtrain …), seit Oktober 2026. Ganz ausgefallene Züge erscheinen nur, wenn sie vorher schon einmal unterwegs gesehen wurden.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611
datePflichtstringBetriebstag JJJJ-MM-TT

Antwort

Zuglauf mit stops als Liste der Halte und source

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/runs/date" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/runs/date", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/runs/date",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Stand eines Zuges

GET/v1/trains/{train}/statusEimer standard

Was gerade auf der Tafel des Zuges stünde: vor der Abfahrt am ersten Halt, unterwegs am nächsten Halt, danach am Ziel. Ohne date die Fahrt, die gerade läuft (auch ein Nachtzug vom Vortag), sonst die von heute. Dazu die Meldungen wie im Laufband am Bahnsteig.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)

Antwort

Objekt { date, train, state, sentence, station, time, platform, platform_changed, via, destination, arrival, notices, complete, source }. state: scheduled, running, arrived oder cancelled; station ist der Bahnhof der Tafel, time die Zeit dort { scheduled, actual, delay }, arrival die Ankunft am Ziel, notices die Texte des Laufbands.

{
  "date": "2026-10-16",
  "train": {
    "name": "ICE 590",
    "category": "ICE",
    "number": "590"
  },
  "state": "running",
  "sentence": "Unterwegs, nächster Halt Erfurt Hbf",
  "station": {
    "id": "8010101",
    "name": "Erfurt Hbf"
  },
  "time": {
    "scheduled": "2026-10-17T00:29:00+02:00",
    "actual": "2026-10-17T00:59:00+02:00",
    "delay": 30
  },
  "platform": "10",
  "platform_changed": false,
  "via": [],
  "destination": {
    "id": "8010205",
    "name": "Leipzig Hbf"
  },
  "arrival": {
    "scheduled": "2026-10-17T01:45:00+02:00",
    "actual": "2026-10-17T02:07:00+02:00",
    "delay": 22
  },
  "notices": [
    "ca. 30 Minuten später",
    "Grund: Verspätetes Personal aus vorheriger Fahrt"
  ],
  "complete": false,
  "source": "live"
}

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/status" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/status", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/status",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Stand eines Zuges als Bild

GET/v1/trains/{train}/status.pngEimer bild

Der Stand als Bild für Chats und Anzeigen: oben der Zug mit dem Bild seiner Baureihe (sofern bekannt), darunter die Tafel mit Zeit, Laufband, Unterwegshalten, Ziel und Gleis.

Info

Eigener Eimer bild: 10 Bilder pro Minute.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)

Antwort

PNG, 1200 × 640 Pixel. Header X-Run-Date (Betriebstag), X-State (wie state beim Stand) und X-Arrival-Delay (Minuten am Ziel, wenn bekannt)

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/status.png" \
  -H "Authorization: Bearer $BT_SCHLUESSEL" --output tafel.png
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/status.png", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const png = Buffer.from(await antwort.arrayBuffer());
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/status.png",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
open("${datei}", "wb").write(antwort.content)

Karte eines Zuges

GET/v1/trains/{train}/map.pngEimer bild

Der Laufweg als Karte (Gleisverlauf aus der Fahrplanauskunft) mit den Halten, dem roten Punkt, wo der Zug gerade ist, und den Einschränkungen aus der Streckeninfo, die während der Fahrt am Weg gelten: Sperrungen rot gestrichelt, andere Einschränkungen orange. view=train zeigt den Ausschnitt um den Zug und den nächsten Halt mit der Entfernung.

Info

Eigener Eimer bild. view=train ist genau der Ausschnitt, den man aus der Gesamtansicht um zoom vergrößert (siehe Einschränkungen am Laufweg, Feld map).

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)
viewstringAusschnittoverview ganzer Laufweg, train um den Zug und den nächsten HaltStandard: overview

Antwort

PNG, 1200 × 560 Pixel. Header X-Remaining-Km (Entfernung zum nächsten Halt, wenn der Zug fährt) und X-Restrictions (Zahl der Einschränkungen am Weg)

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/map.png" \
  -H "Authorization: Bearer $BT_SCHLUESSEL" --output umgebung.png
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/map.png", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const png = Buffer.from(await antwort.arrayBuffer());
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/map.png",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
open("${datei}", "wb").write(antwort.content)

Einschränkungen am Laufweg

GET/v1/trains/{train}/restrictionsEimer standard

Baustellen und Störungen aus der Streckeninfo, die während der Fahrt am Laufweg des Zuges gelten: Sperrungen, Gegengleis, längere Fahrzeiten, Umleitungen, Ausfälle. Dazu, ob sie noch vor dem Zug liegen, und die Daten der Karte.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)

Antwort

Objekt { date, train, restrictions, map }; restrictions: { id, type, effect, effect_text, title, from, to, ahead } (ahead: liegt noch vor dem Zug), Einzelheiten unter Einschränkung abrufen; map: { zoom, center, remaining_km, next_stop }

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/restrictions" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/restrictions", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/restrictions",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Wagenreihung eines Zuges

GET/v1/trains/{train}/formationEimer standard

Die Wagenreihung an einem Halt des Zuges, aus den Daten der DB: Abschnitte des Bahnsteigs, jeder Wagen mit Nummer, Klasse, Abschnitt, ungefährer Lage in Prozent der Bahnsteiglänge und Ausstattung (Bordrestaurant, Ruhebereich, Familie, Kleinkind, Rollstuhl, Fahrrad), dazu Triebzug und Baureihe. Ohne station der nächste Halt mit Abfahrt.

Info

Die DB kennt die Wagenreihung meist ab dem Vortag. Wir fragen sparsam an und merken uns die Ergebnisse eine Weile.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)
stationstringEVA-Nummer des Halts (Standard: nächster Halt mit Abfahrt)

Antwort

Objekt { train, date, station, departure, platform, platform_scheduled, matches_schedule, sectors, groups, outside_platform }; outside_platform: Wagen, die ganz (fully: true) oder teilweise außerhalb des Bahnsteigs halten { number, fully }, Lage unter 0 oder über 100 %; groups[].carriages[]: { number, class, sector, position, closed, end_car, features }, features wie bei der Wagenreihung und zusätzlich infant_cabin

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/formation" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/formation", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/formation",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Wagenreihung als Bild

GET/v1/trains/{train}/formation.svgEimer bild

Die Wagenreihung als Zeichnung wie auf der Zugseite: oben die Abschnitte wie die Schilder am Bahnsteig, darunter die Wagen an ihrer Stelle, 1. Klasse gelb, Bordrestaurant rot, darunter die Zeichen der Ausstattung.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)
stationstringEVA-Nummer des Halts (Standard: nächster Halt mit Abfahrt)

Antwort

SVG, 1000 Einheiten breit, Höhe je nach Zugteilen (etwa 140)

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/formation.svg" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/formation.svg", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/formation.svg",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Fahrgastrechte

GET/v1/trains/{train}/passenger-rightsEimer standard

Was Fahrgästen dieses Zuges zusteht: Verspätung an jedem Halt mit dem Anteil des Fahrpreises, den es dort zurückgibt (ab 60 Minuten 25 %, ab 120 Minuten 50 %), ob die Zugbindung aufgehoben ist (ab 20 Minuten erwarteter Verspätung) und die Links zum Antrag.

Info

Maßgeblich ist die Verspätung an deinem eigenen Ziel. Beträge unter 4 € zahlt die Bahn nicht aus; für Zeitkarten und das Deutschlandticket gelten eigene Regeln. Keine Rechtsberatung.

Pfad-Parameter

FeldTypBeschreibung
trainPflichtstringZug, z. B. ICE_611, ICE 611 oder nur 611

Query-Parameter

FeldTypBeschreibung
datestringBetriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt)

Antwort

Objekt { date, train, complete, cancelled, delay_at_destination, max_arrival_delay, compensation_percent_at_destination, ticket_binding_lifted, stops, rules, info_url, form_url }; stops: { station, arrival_delay, compensation_percent }

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/trains/train/passenger-rights" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/trains/train/passenger-rights", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/trains/train/passenger-rights",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Im Archiv suchen

GET/v1/archive/searchEimer standard

Alle aufgezeichneten Züge eines Tages, auf Wunsch nur durch einen Bahnhof, ab einer Verspätung, nur mit Ausfällen oder nur eine Gattung. Mit station stehen die Zeiten und das Gleis an diesem Bahnhof in here.

Query-Parameter

FeldTypBeschreibung
datePflichtstringBetriebstag JJJJ-MM-TT
stationstringNur Züge über diesen Bahnhof (EVA-Nummer)
categorystringNur diese Gattung, z. B. ICE
min_delayintegerNur Züge mit mindestens so viel Verspätung (größte unterwegs)0 bis 1440
cancelledboolNur Züge mit AusfällenStandard: false
limitintegerHöchstens so vieleStandard: 1001 bis 500

Antwort

Liste von Zuglauf, mit station zusätzlich here: { arrival, departure, platform }

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/archive/search?date=wert" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/archive/search?date=wert", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/archive/search?date=wert",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()

Stand des Archivs

GET/v1/archiveEimer standard

Was das Zugarchiv enthält: Zahl der Läufe, Halte und Züge, erster und letzter Tag, Größe der Datenbank.

Antwort

Objekt { runs, stops, trains, first_day, last_day, bytes, recording }

Beispiel

curl
curl "https://developer.bahnhoftafel.de/v1/archive" \
  -H "Authorization: Bearer $BT_SCHLUESSEL"
JavaScript
const antwort = await fetch("https://developer.bahnhoftafel.de/v1/archive", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();
Python
import os, requests

antwort = requests.get(
    "https://developer.bahnhoftafel.de/v1/archive",
    headers={"Authorization": f"Bearer {os.environ['BT_SCHLUESSEL']}"},
    timeout=30,
)
daten = antwort.json()