Die öffentliche API.
Dieselben Daten, die auch die Apps und diese Website verwenden. Kein Schlüssel nötig, offene CORS-Freigabe, faire Limits.
Grundregeln
https://api.oeffigo.appAccess-Control-Allow-Origin: *.429 mit Retry-After: 30.no-store. Erfolge je nachdem, wie schnell sich die Daten bewegen: max-age=10 als Regel, 15 für /v1/vehicles, 60 im Browser und 300 am Edge für /v1/history. POST /v1/predictions/batch ist no-store — die Antwort hängt am gesendeten Body und gehört in keinen geteilten Cache. Verlass dich auf den Header, nicht auf diesen Absatz./v2 zählt getrennt und nennt seine Version in jeder Antwort im Header X-OeffiGo-Contract./v2 ist fertig — fünfzehn Routen, versionierter Vertrag, maschinenlesbares Schema unter /v2/schema, Routenliste unter /v2/meta. Beides ist offen einsehbar. Aufrufen kann man die Routen von außen trotzdem nicht: sie weisen jede Anfrage ab, die einen Origin mitschickt, und verlangen ein Installations-Token, das nur die Apps erhalten. Das ist Absicht — hinter /v2 hängt ein vertraglich begrenztes Tageskontingent beim Datenlieferanten, und eine offene Route darauf wäre eine Route, die irgendwann für alle leer ist./v1-Endpunkte sind die offene Fläche: schlichte GETs, CORS erlaubt, ohne Zugangsdaten nutzbar. Sie bleiben. Sie sind nicht das, was die Apps sprechen — die sind auf /v2 umgezogen —, aber genau deshalb hängen sie auch nicht am Providerkontingent. Zusätzliche Felder können jederzeit auftauchen; ignoriere unbekannte Felder.{ "error": "code" } mit passendem HTTP-Status.Endpunkte
Kurzer Lebenszeichen-Check.
Antwortet mit 200, solange der Worker einen frischen erfolgreichen Zyklus hinter sich hat, sonst mit 503. Gedacht für Monitoring, nicht für Datenabfragen.
Anfrage
curl -s https://api.oeffigo.app/v1/healthAntwort
{
"ok": true,
"version": "5dc1a29",
"predictionsLive": 1312,
"confidentPredictions": 1190
}Betriebszustand aller Komponenten.
Liefert den Gesamtzustand, eine Komponentenliste und je Datenweg eine Verfügbarkeits-Historie in Halbstundenschritten. Diese Seite und oeffigo.app/status lesen dieselbe Quelle.
Anfrage
curl -s https://api.oeffigo.app/v1/statusAntwort
{
"generatedAt": "2026-07-26T13:25:06.754Z",
"overall": "operational",
"components": [
{ "id": "api", "name": "…", "status": "operational" }
],
"measurement": { "mode": "official_realtime" }
}Zuverlässigkeits-Auswertung aus offiziellen Ist-Zeiten.
Summen, Tagesverlauf, Linien und ein Wochentag×Stunde-Muster. Gezählt werden einzelne Halte, nicht ganze Fahrten. Ein fehlender Datenpunkt gilt nie als Ausfall — Ausfälle stammen ausschließlich aus expliziten Ereignissen.
| Parameter | Typ | Bedeutung |
|---|---|---|
from | ISO date | Beginn des Zeitraums. |
to | ISO date | Ende des Zeitraums. Maximal 366 Tage Spanne. |
line | string | Auf eine Linie einschränken. |
source | string | Auf eine Datenquelle einschränken: wiener_linien, trias, stmk_gtfs_rt. |
Anfrage
curl -s "https://api.oeffigo.app/v1/history?from=2026-07-15&to=2026-07-26&line=U1"Antwort
{
"period": { "from": "2026-07-15", "to": "2026-07-26" },
"totals": {
"onTimeShare": 0.9556,
"avgDelayMin": 0.57,
"late10Share": 0.007
},
"officialRealtime": {
"daily": [ { "day": "2026-07-26", "events": 18109, "on_time_pct": 97.4 } ],
"lines": [ { "line": "U1", "events": 39970, "on_time_pct": 96 } ],
"heatmap": [ { "dow": 1, "hour": 8, "avg_delay_min": 0.6 } ]
}
}- Fünf Minuten am Edge cachebar, unterstützt ETag und 304.
- `dow` ist ISO: 1 = Montag … 7 = Sonntag.
Eigene Verspätungsprognosen aus offizieller Echtzeit.
Nur Einträge mit hoher oder mittlerer Sicherheit. Jeder Eintrag verfällt spätestens acht Minuten nach der letzten echten Beobachtung — ältere Werte werden nicht ausgeliefert. <strong>Ein Filter ist Pflicht</strong>: ohne einen kommt <code>400 missing_query</code>, denn „alle Prognosen“ ist keine Frage, die dieser Endpunkt beantwortet.
| Parameter | Typ | Bedeutung |
|---|---|---|
lat + lon | number | Umkreis, optional mit radius. Einer der vier Filter. |
line | string | Linienlabel, z. B. U1. Einer der vier Filter. |
jid | string | Eine Fahrt-Referenz. Einer der vier Filter. |
jids | string[] | Bis zu 40 Fahrt-Referenzen, komma-getrennt. Einer der vier Filter. |
radius | int | Nur zusammen mit lat + lon. |
limit | int | Höchstens 200. Ersetzt keinen Filter. |
Anfrage
curl -s "https://api.oeffigo.app/v1/predictions?line=U1&limit=50" -H 'If-None-Match: "abc123"'Antwort
{
"generatedAt": "2026-07-26T13:25:06.754Z",
"count": 2,
"predictions": [
{ "jid": "og1.…", "delayMin": 2, "confidence": "high" }
]
}- Antworten tragen ein schwaches ETag. Mit If-None-Match bekommst du ein 304 ohne Body, solange sich der Snapshot nicht geändert hat — die batteriefreundliche Art zu pollen.
Viele Fahrt-Referenzen auf einmal abfragen.
Fahrt-Referenzen sind lang und gehören nicht in eine URL. Für mehr als eine Handvoll ist das der richtige Weg.
Anfrage
curl -s -X POST https://api.oeffigo.app/v1/predictions/batch \
-H 'content-type: application/json' \
-d '{"jids":["og1.…","og1.…"]}'Antwort
{
"generatedAt": "2026-07-26T13:25:06.754Z",
"count": 2,
"predictions": [ … ]
}Begrenzter Kartenausschnitt mit Fahrzeugen.
Verlangt entweder eine Bounding-Box oder eine Liste von Fahrt-Referenzen — ohne Filter gibt es keine Antwort. Einträge sind höchstens acht Minuten alt. Das Feld `source` sagt dir, was ein leeres Ergebnis bedeutet.
| Parameter | Typ | Bedeutung |
|---|---|---|
minLat, minLon, maxLat, maxLon | number | Sichtbarer Kartenausschnitt — alle vier oder keiner. |
jids | string[] | Kommagetrennte Fahrt-Referenzen. Der Server nimmt bis zu 500 an, praktisch begrenzt die URL-Länge auf rund 40. Löst keinen Abruf aus. |
limit | number | 1–1.000, Standard 500. |
Anfrage
curl -s "https://api.oeffigo.app/v1/vehicles?minLat=48.18&minLon=16.30&maxLat=48.24&maxLon=16.42"Antwort
{
"generatedAt": "2026-08-03T19:25:06.754Z",
"count": 242,
"source": "ondemand_live",
"measurementMode": "official_realtime",
"vehicles": [ { "jid": "og1.…", "lat": 48.2, "lon": 16.37 } ]
}- `ondemand_live` mit leerer Liste heißt „gerade keine Fahrzeuge“, nicht „Dienst aus“. `ondemand_capped` heißt „Live-Fahrzeuge vorübergehend nicht verfügbar“.
Wiener U-Bahn-Echtzeit, gecacht.
Nur Stationen aus einer festen Liste — der Endpunkt ist bewusst kein offener Proxy auf den Betreiber-Monitor. Datenquelle: Stadt Wien, CC BY 4.0.
| Parameter | Typ | Bedeutung |
|---|---|---|
diva | int | Stationskennung aus der Liste. |
Anfrage
curl -s "https://api.oeffigo.app/v1/wiener-linien/metro?diva=60200657"Antwort
{
"generatedAt": "2026-08-03T19:16:51.814Z",
"status": "ok",
"departures": [
{ "line": "1", "towards": "Stefan-Fadinger-Platz",
"plannedAt": "2026-08-03T19:23:30.000Z",
"realAt": "2026-08-03T19:26:50.000Z" }
]
}- Die Verspätung steht nicht als Zahl drin — sie ist die Differenz aus
realAtundplannedAt. Beides sind ISO-Zeitstempel, keine Millisekunden. - Kann
503 source_standbyantworten, wenn die Wiener-Linien-Quelle gerade abgeschaltet ist. Das ist kein Ausfall, sondern eine bewusste Bremse — probier es später erneut.
Servergesteuerte Meldungen für die Apps.
Erlaubt es, Hinweise ohne App-Update auszuspielen. Geschlossene und abgelaufene Meldungen sind nicht enthalten.
Anfrage
curl -s https://api.oeffigo.app/v1/announcementsAntwort
{
"generatedAt": "2026-07-26T13:25:06.754Z",
"announcements": [ { "id": "…", "title": "…", "body": "…" } ]
}Was die API bewusst nicht ist.
Die typisierten Routen, über die die Apps Fahrplan- und Auskunftsdaten holen, sind fest an die Apps gebunden und nicht Teil dieser Dokumentation. Sie sind kein allgemeiner Proxy auf fremde Anbieter, und Zugangsdaten dafür verlassen den Server nie. Bitte baue nichts, das darauf angewiesen ist.
Fahrt-Referenzen (og1.…) sind undurchsichtig und an einen Anbieter gebunden. Sie dürfen nicht entpackt, umgebaut oder zwischen Netzen gemischt werden — gib sie unverändert zurück.
Die API ist offen, damit man damit etwas bauen kann. Bleib in den Limits, cache Antworten, und wenn du Wiener Echtzeitdaten weiterverwendest, nenne die Quelle: Stadt Wien — data.wien.gv.at, CC BY 4.0.