BYTETOOLS

Swiss Public Transport API

Free Swiss public transport API with no key: connections, departure boards and station search across trains, buses, trams and boats, with live delay data. Tested example included.

No API key requiredCORS enabledHTTPSFree tier

Endpoint tested and returned HTTP 200 on 2026-08-21

What is the Swiss Public Transport API?

The Swiss public transport API (transport.opendata.ch) is a free, key-free journey planner covering every train, bus, tram, funicular and boat in Switzerland. It returns connections between any two stops with departure and arrival times, platforms, changes and live delay prognosis.

Switzerland's public transport is famously integrated, and so is its data: one API covers SBB trains, regional buses, city trams, mountain funiculars and lake boats through a single search. You can plan a journey from a village bus stop to a major station without knowing which operators are involved.

Two things make this API notably pleasant to use. Station names work as free text — "Zurich" resolves without you needing to look up ID 8503000 first — which removes the lookup step most transport APIs force on you. And every leg carries a `prognosis` object holding live expected times alongside the scheduled ones, plus a `delay` field in minutes, so real-time status comes back in the same call as the timetable rather than from a second endpoint.

Quick facts

Base URL
https://transport.opendata.ch/v1
Authentication
No API key or account. It is a community-run wrapper over the official Swiss timetable data, not an SBB-operated service.
Rate limit
Roughly 1,000 requests per day per IP. Heavy users are directed to the official opentransportdata.swiss platform.
Pricing
Free.
CORS
Enabled — callable directly from browser JavaScript
Official docs
Read the docs

How to use the Swiss Public Transport API

Every request below was executed against the live API on 2026-08-21, and the response shown is the real body it returned — not an illustration.

1. Find the next connection from Zurich to Bern

GET https://transport.opendata.ch/v1/connections?from=Zurich&to=Bern&limit=1

curl
curl 'https://transport.opendata.ch/v1/connections?from=Zurich&to=Bern&limit=1'
JavaScript (fetch)
const res = await fetch("https://transport.opendata.ch/v1/connections?from=Zurich&to=Bern&limit=1");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

res = requests.get("https://transport.opendata.ch/v1/connections?from=Zurich&to=Bern&limit=1", timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
{
  "connections": [
    {
      "from": {
        "station": {
          "id": "8503000",
          "name": "Zürich HB",
          "score": null,
          "coordinate": {
            "type": "WGS84",
            "x": 47.377847,
            "y": 8.540502
          },
          "distance": null
        },
        "arrival": null,
        "arrivalTimestamp": null,
        "departure": "2026-08-21T09:32:00+0200",
        "departureTimestamp": 1787297520,
        "delay": 0,
        "platform": "32",
        "prognosis": {
          "platform": null,
          "arrival": null,
          "departure": "2026-08-21T09:32:00+0200",
          "capacity1st": null,
          "capacity2nd": null
        },
        "realtimeAvailability": null,
        "location": {
          "id": "8503000",
          "name": "Zürich HB",
          "score": null,
          "coordinate": {
            "type": "WGS84",
            "x": 47.377847,
            "y": 8.540502
          },
          "distance": null
        }
      },
      "to": {
        "station": {
          "id": "8507000",
          "name": "Bern",
          "score": null,
          "coordinate": {
            "type": "WGS84",
            "x": 46.948823,
            "y": 7.439123
          },
          "distance": null
        },
        "arrival": "2026-08-21T10:28:00+0200",
        "arrivalTimestamp": 1787300880,
        "departure": null,
        "departureTimestamp": null,
        "delay": null,
        "platform": "8",
        "prognosis": {
          "platform": null,
          "arrival": null,
          "departure": null,

Parameters

ParameterTypeRequiredDescription
fromqueryRequiredDeparture stop. Accepts a free-text station name or a stop id. Zurich
toqueryRequiredDestination stop, in the same format. Bern
limitqueryOptionalHow many connections to return, up to 16. 1
date / timequeryOptionalDeparture date (`YYYY-MM-DD`) and time (`HH:MM`). Defaults to now. 2026-08-21
isArrivalTimequeryOptionalSet to 1 to treat `time` as a desired arrival rather than departure. 1
transportationsqueryOptionalRestrict modes: `train`, `tram`, `ship`, `bus`, `cableway`. train

Response fields

connections[].from / toobject
Origin and destination legs, each with the resolved `station` (id, name, coordinates), platform and timestamps.
departure / arrivalstring
Scheduled times as ISO 8601 with a Swiss timezone offset.
departureTimestampinteger
The same moment as Unix seconds, which is easier to compare than the offset string.
delayinteger
Live delay in minutes. Zero means on time; null means no real-time data is available for that leg.
prognosisobject
Live expected platform and times, which override the scheduled values when they differ.
platformstring
Departure platform. Check `prognosis.platform` too — last-minute platform changes appear there first.
sectionsarray
The individual legs of a journey, including which service operates each and where changes occur.

What you can build with the Swiss Public Transport API

  • Build a departure board for a Swiss station or office lobby
  • Add journey planning to a Swiss travel or events app
  • Alert commuters when their usual connection is delayed
  • Calculate realistic travel times for scheduling and logistics

Common errors and how to fix them

Ambiguous station name

The free-text name matched several stops.

Fix: Use the `/locations?query=` endpoint to resolve a name to a specific stop id, then pass the id instead.

429

Daily request limit exceeded.

Fix: Cache timetable queries — scheduled times change only when the timetable does. For high volume, move to the official opentransportdata.swiss platform.

Empty connections array

No service runs between those stops at that time.

Fix: Late at night or on Sundays many routes do not operate. Widen the time window before assuming an error.

Swiss Public Transport API — frequently asked questions

Is the Swiss transport API free?

Yes, free with no API key, at roughly 1,000 requests per day per IP. It is a community-run wrapper over official Swiss timetable data; heavier users are pointed at the official opentransportdata.swiss platform.

Does it include live delays?

Yes. Every leg carries a `delay` field in minutes and a `prognosis` object with live expected times and platforms. That means real-time status arrives in the same response as the timetable, without a second call.

Do I need station IDs?

No, and that is one of its nicer properties — `from=Zurich` works directly. If a name is ambiguous, resolve it first through the `/locations` endpoint and pass the returned stop id instead.

What transport modes are covered?

All of them: SBB and regional trains, city trams, buses, funiculars, cable cars and lake boats, searchable together. The `transportations` parameter narrows to specific modes when you need it.

Tools that pair with this API

Swiss Public Transport is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 2026-08-21; always check the official documentation before relying on this API in production, as terms and limits can change.