Entur JourneyPlanner API
Free Norwegian journey planner API with no key: plan multi-modal trips across every operator in Norway with a single GraphQL query. Tested example and live response included.
Endpoint tested and returned HTTP 200 on 2026-08-21
What is the Entur JourneyPlanner API?
Entur's JourneyPlanner is a free, key-free GraphQL API covering all public transport in Norway. One query plans an end-to-end journey across trains, buses, trams, ferries, flights and walking legs, returning each leg with its mode, operator, line, distance and expected times.
Norway consolidated every operator's timetable into one national dataset and put a single planner in front of it, which produces itineraries that would be several separate lookups elsewhere. The example below asks for Oslo to Bergen and gets back a genuinely multi-modal answer — airport express train, a walk through the terminal, a domestic flight, another walk and an airport bus — because the planner treats air as just another mode rather than a different product.
There is no API key, but there is an etiquette requirement: every request must carry an `ET-Client-Name` header identifying your application, conventionally as `company-application`. Entur uses it for support and abuse handling and will throttle unidentified traffic. Being GraphQL, you choose your own response shape, which is the main practical advantage here — a departure board can ask for four fields while a full planner asks for fifty, from the same endpoint.
Quick facts
- Base URL
https://api.entur.io/journey-planner/v3- Authentication
- No API key or account. An `ET-Client-Name` header identifying your application is mandatory; requests without it are throttled.
- Rate limit
- No published numeric quota for identified clients. Entur asks that you send `ET-Client-Name`, cache aggressively and avoid polling loops.
- Pricing
- Free. Norwegian national public transport data under an open licence.
- CORS
- Enabled — callable directly from browser JavaScript
- Official docs
- Read the docs
How to use the Entur JourneyPlanner 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. Plan a multi-modal journey from Oslo to Bergen
POST https://api.entur.io/journey-planner/v3/graphql
curl -X POST 'https://api.entur.io/journey-planner/v3/graphql' \
-H 'Content-Type: application/json' \
-H 'ET-Client-Name: bytevancer-bytetools' \
-d '{"query":"{trip(from:{place:\"NSR:StopPlace:59872\"},to:{place:\"NSR:StopPlace:59983\"},numTripPatterns:1){tripPatterns{expectedStartTime expectedEndTime duration legs{mode distance line{publicCode name} fromPlace{name} toPlace{name}}}}}"}'const res = await fetch("https://api.entur.io/journey-planner/v3/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
"ET-Client-Name": "bytevancer-bytetools",
},
body: JSON.stringify({"query":"{trip(from:{place:\"NSR:StopPlace:59872\"},to:{place:\"NSR:StopPlace:59983\"},numTripPatterns:1){tripPatterns{expectedStartTime expectedEndTime duration legs{mode distance line{publicCode name} fromPlace{name} toPlace{name}}}}}"}),
});
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);import requests
headers = {
"Content-Type": "application/json",
"ET-Client-Name": "bytevancer-bytetools",
}
payload = {"query":"{trip(from:{place:\"NSR:StopPlace:59872\"},to:{place:\"NSR:StopPlace:59983\"},numTripPatterns:1){tripPatterns{expectedStartTime expectedEndTime duration legs{mode distance line{publicCode name} fromPlace{name} toPlace{name}}}}}"}
res = requests.post("https://api.entur.io/journey-planner/v3/graphql", headers=headers, json=payload, timeout=20)
res.raise_for_status()
print(res.json()){
"data": {
"trip": {
"tripPatterns": [
{
"expectedStartTime": "2026-08-21T10:30:00+02:00",
"expectedEndTime": "2026-08-21T13:19:19+02:00",
"duration": 10159,
"legs": [
{
"mode": "rail",
"distance": 47631.0,
"line": {
"publicCode": "FLY2",
"name": "FLY2"
},
"fromPlace": {
"name": "Oslo S"
},
"toPlace": {
"name": "Oslo lufthavn stasjon"
}
},
{
"mode": "foot",
"distance": 246.46,
"line": null,
"fromPlace": {
"name": "Oslo lufthavn stasjon"
},
"toPlace": {
"name": "Oslo lufthavn"
}
},
{
"mode": "air",
"distance": 324009.0,
"line": {
"publicCode": null,
"name": "Oslo-Bergen"
},
"fromPlace": {
"name": "Oslo lufthavn"
},
"toPlace": {
"name": "Bergen lufthavn"
}
},
{
"mode": "foot",
"distance": 192.43,
"line": null,
"fromPlace": {
"name": "Bergen lufthavn"
},
"toPlace": {
"name": "Bergen lufthavn"
}
},
{Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ET-Client-Name | header | Required | Identifies your application, conventionally `company-application`. Required. bytevancer-bytetools |
query | graphql | Required | The GraphQL query. `trip(from:, to:)` is the journey planning entry point. {trip(from:{place:"NSR:StopPlace:59872"}...)} |
from / to | graphql | Required | Origin and destination as `{place: "NSR:StopPlace:id"}` or `{coordinates: {latitude, longitude}}`. NSR:StopPlace:59872 |
numTripPatterns | graphql | Optional | How many alternative itineraries to return. 3 |
dateTime | graphql | Optional | ISO 8601 departure time. Defaults to now. 2026-08-21T10:00:00+02:00 |
modes | graphql | Optional | Restrict the transport modes considered, for example rail and bus only. {transportModes:[{transportMode:rail}]} |
(geocoder) | path | Optional | `/geocoder/v1/autocomplete?text=` resolves a place name to the `NSR:StopPlace:` id the planner needs. |
Response fields
data.trip.tripPatternsarray- The alternative itineraries found, best first.
tripPatterns[].expectedStartTime / expectedEndTimestring- ISO 8601 with a Norwegian offset. These are expected rather than scheduled — real-time data is already applied.
tripPatterns[].durationinteger- Total journey time in seconds, including waiting and interchange.
tripPatterns[].legsarray- The individual legs, in order.
legs[].modestring- `rail`, `bus`, `tram`, `water`, `air`, `metro` or `foot`. Walking legs are included explicitly.
legs[].distancefloat- Leg distance in metres. The air leg in the example is 324 kilometres.
legs[].lineobject- Service line with `publicCode` and `name`. Null on walking legs — check before dereferencing.
legs[].fromPlace / toPlaceobject- Named endpoints of each leg, which is what makes the itinerary readable.
What you can build with the Entur JourneyPlanner API
- Plan door-to-door journeys anywhere in Norway
- Build a departure board for a Norwegian stop
- Show travel time and interchange count between two towns
- Include ferries and domestic flights in a single itinerary
- Request exactly the fields a screen needs, and nothing more
Common errors and how to fix them
Throttled or rejected requests
The `ET-Client-Name` header is missing.
Fix: Send it on every request, in the form `company-application`. It is not authentication, but Entur treats unidentified traffic as abusable.
Null pointer on leg.line
Walking legs have no line.
Fix: Guard every access to `line`. A typical Norwegian itinerary has more foot legs than transit legs.
GraphQL errors array with HTTP 200
GraphQL reports query errors in the body, not the status code.
Fix: Check for an `errors` key on every response. A malformed field name returns 200 with the error inside.
Unknown place id
The `NSR:StopPlace:` identifier is wrong or does not exist.
Fix: Resolve names through the geocoder endpoint first, or pass coordinates instead of an id.
Entur JourneyPlanner API — frequently asked questions
Is the Entur API free?
Yes, free with no key or account. The only requirement is an `ET-Client-Name` header identifying your application, which Entur uses for support and to manage abuse.
Does it cover every operator in Norway?
Yes. Entur aggregates the national timetable across all public transport operators — rail, bus, tram, metro and ferry — and includes domestic flights as an air mode in journey planning.
Why GraphQL rather than REST?
Because journey data is deeply nested and different clients need wildly different slices of it. A departure board can request four fields and a full planner fifty, from the same endpoint, without either over-fetching.
How do I find a stop place id?
Use the Entur geocoder at `/geocoder/v1/autocomplete?text=`, which returns `NSR:StopPlace:` identifiers for matching places. The planner also accepts raw coordinates if you would rather skip the lookup.
Tools that pair with this API
Time Duration Calculator
Add or subtract hours, minutes and seconds, or sum a list of durations into a total shown in h:m:s and in total seconds. Free and 100% in-browser.
Timestamp Converter
Convert timestamps to human-readable dates and dates back to timestamps. Auto-detects seconds vs milliseconds, shows local, UTC and ISO 8601 formats.
Time Zone Converter
Convert any date and time between world time zones. See UTC offsets, daylight saving handled automatically, and compare multiple zones at once.
Entur JourneyPlanner 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.