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
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag JJJJ-MM-TT (Tag der Abfahrt am ersten Halt) |
train | object | { name, category, number }, z. B. ICE 611 |
operator | ?string | Betreiber |
origin | ?object | { id, name } |
destination | ?object | { id, name } |
departure | ?string | Geplante Abfahrt am ersten Halt |
arrival | ?string | Geplante Ankunft am letzten Halt |
arrival_delay | ?integer | Verspätung am Ziel in Minuten |
max_delay | ?integer | Größte Verspätung unterwegs |
cancelled | string | no, 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 |
complete | boolean | true, wenn der Zug angekommen ist und der Tag fertig aufgezeichnet |
source | string | Nur beim einzelnen Lauf: archive, live (heute, aus der Auskunft) oder plan (künftiger Tag) |
stops | integer | 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
/v1/trains/{train}/runsEimer standardAlle 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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
from | string | Ab diesem Tag, Standard: vor 30 Tagen |
to | string | Bis zu diesem Tag, Standard: heute |
limit | integer | Hö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 "https://developer.bahnhoftafel.de/v1/trains/train/runs" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/trains/{train}/runs/{date}Eimer standard, 2 MarkenJeder 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).
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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
datePflicht | string | Betriebstag JJJJ-MM-TT |
Antwort
Zuglauf mit stops als Liste der Halte und source
Beispiel
curl "https://developer.bahnhoftafel.de/v1/trains/train/runs/date" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/trains/{train}/statusEimer standardWas 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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag 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 "https://developer.bahnhoftafel.de/v1/trains/train/status" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/trains/{train}/status.pngEimer bildDer 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.
Eigener Eimer bild: 10 Bilder pro Minute.
Pfad-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag 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 "https://developer.bahnhoftafel.de/v1/trains/train/status.png" \
-H "Authorization: Bearer $BT_SCHLUESSEL" --output tafel.pngconst 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());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
/v1/trains/{train}/map.pngEimer bildDer 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.
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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt) |
view | string | Ausschnittoverview 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 "https://developer.bahnhoftafel.de/v1/trains/train/map.png" \
-H "Authorization: Bearer $BT_SCHLUESSEL" --output umgebung.pngconst 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());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
/v1/trains/{train}/restrictionsEimer standardBaustellen 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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag 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 "https://developer.bahnhoftafel.de/v1/trains/train/restrictions" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/trains/{train}/formationEimer standardDie 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.
Die DB kennt die Wagenreihung meist ab dem Vortag. Wir fragen sparsam an und merken uns die Ergebnisse eine Weile.
Pfad-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt) |
station | string | EVA-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 "https://developer.bahnhoftafel.de/v1/trains/train/formation" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/trains/{train}/formation.svgEimer bildDie 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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag JJJJ-MM-TT (Standard: die aktuelle Fahrt) |
station | string | EVA-Nummer des Halts (Standard: nächster Halt mit Abfahrt) |
Antwort
SVG, 1000 Einheiten breit, Höhe je nach Zugteilen (etwa 140)
Beispiel
curl "https://developer.bahnhoftafel.de/v1/trains/train/formation.svg" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/trains/{train}/passenger-rightsEimer standardWas 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.
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
| Feld | Typ | Beschreibung |
|---|---|---|
trainPflicht | string | Zug, z. B. ICE_611, ICE 611 oder nur 611 |
Query-Parameter
| Feld | Typ | Beschreibung |
|---|---|---|
date | string | Betriebstag 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 "https://developer.bahnhoftafel.de/v1/trains/train/passenger-rights" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/archive/searchEimer standardAlle 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
| Feld | Typ | Beschreibung |
|---|---|---|
datePflicht | string | Betriebstag JJJJ-MM-TT |
station | string | Nur Züge über diesen Bahnhof (EVA-Nummer) |
category | string | Nur diese Gattung, z. B. ICE |
min_delay | integer | Nur Züge mit mindestens so viel Verspätung (größte unterwegs)0 bis 1440 |
cancelled | bool | Nur Züge mit AusfällenStandard: false |
limit | integer | Höchstens so vieleStandard: 1001 bis 500 |
Antwort
Liste von Zuglauf, mit station zusätzlich here: { arrival, departure, platform }
Beispiel
curl "https://developer.bahnhoftafel.de/v1/archive/search?date=wert" \
-H "Authorization: Bearer $BT_SCHLUESSEL"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();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
/v1/archiveEimer standardWas 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 "https://developer.bahnhoftafel.de/v1/archive" \
-H "Authorization: Bearer $BT_SCHLUESSEL"const antwort = await fetch("https://developer.bahnhoftafel.de/v1/archive", {
method: "GET",
headers: { Authorization: `Bearer ${process.env.BT_SCHLUESSEL}`, },
});
const daten = await antwort.json();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()