00Entwicklerv1

Die öffentliche API.

Dieselben Daten, die auch die Apps und diese Website verwenden. Kein Schlüssel nötig, offene CORS-Freigabe, faire Limits.

Grundregeln

Basis-URLhttps://api.oeffigo.app
CORSOffen — jede Antwort trägt Access-Control-Allow-Origin: *.
Rate-Limit120 Anfragen pro Minute und IP. Darüber gibt es 429 mit Retry-After: 30.
CachingFehler immer 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.
VersionierungBrechende Änderungen bekommen einen neuen Pfad. Zusätzliche Felder können jederzeit auftauchen — ignoriere unbekannte Felder. Der App-Vertrag auf /v2 zählt getrennt und nennt seine Version in jeder Antwort im Header X-OeffiGo-Contract.
<code>/v2</code> ist der App-Vertrag, keine offene API/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.
Was das für <code>/v1</code> heißtDie hier dokumentierten /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.
FehlerformatImmer { "error": "code" } mit passendem HTTP-Status.

Endpunkte8

01GET/v1/health

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/health

Antwort

{
  "ok": true,
  "version": "5dc1a29",
  "predictionsLive": 1312,
  "confidentPredictions": 1190
}
02GET/v1/status

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/status

Antwort

{
  "generatedAt": "2026-07-26T13:25:06.754Z",
  "overall": "operational",
  "components": [
    { "id": "api", "name": "…", "status": "operational" }
  ],
  "measurement": { "mode": "official_realtime" }
}
03GET/v1/history

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.

ParameterTypBedeutung
fromISO dateBeginn des Zeitraums.
toISO dateEnde des Zeitraums. Maximal 366 Tage Spanne.
linestringAuf eine Linie einschränken.
sourcestringAuf 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 } ]
  }
}
04GET/v1/predictions

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.

ParameterTypBedeutung
lat + lonnumberUmkreis, optional mit radius. Einer der vier Filter.
linestringLinienlabel, z. B. U1. Einer der vier Filter.
jidstringEine Fahrt-Referenz. Einer der vier Filter.
jidsstring[]Bis zu 40 Fahrt-Referenzen, komma-getrennt. Einer der vier Filter.
radiusintNur zusammen mit lat + lon.
limitintHö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" }
  ]
}
05POST/v1/predictions/batch

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": [ … ]
}
06GET/v1/vehicles

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.

ParameterTypBedeutung
minLat, minLon, maxLat, maxLonnumberSichtbarer Kartenausschnitt — alle vier oder keiner.
jidsstring[]Kommagetrennte Fahrt-Referenzen. Der Server nimmt bis zu 500 an, praktisch begrenzt die URL-Länge auf rund 40. Löst keinen Abruf aus.
limitnumber1–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 } ]
}
07GET/v1/wiener-linien/metro

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.

ParameterTypBedeutung
divaintStationskennung 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" }
  ]
}
08GET/v1/announcements

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/announcements

Antwort

{
  "generatedAt": "2026-07-26T13:25:06.754Z",
  "announcements": [ { "id": "…", "title": "…", "body": "…" } ]
}
09Nicht öffentlich

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.

10Nutzung & Quellenangabe

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.