# Documentation > Complete documentation for Large Language Models --- ## Document: Timetable Data Daily updated timetable data dumps for public transport in Norway in NeTEx and GTFS formats. URL: /open-data/timetable # Timetable Data import TimetableTable from '../../src/runtime/components/open-data/TimetableTable/TimetableTable' import { Callout } from 'zudoku/components' This page lists all our timetable data dumps which are updated daily. All data dumps have permanent URL's and come as NeTEx or GTFS datasets. NeTEx is the official format for public transport data in Norway and is the most complete in terms of available data. GTFS is a downstream format with only a limited subset of the total data, but we generate datasets for it anyway since GTFS can be easier to use and has a wider distribution among international public transport solutions. GTFS sets come in "extended" and "basic" versions. Please be aware that certain information, important to journey planning, may be lacking in the GTFS files. This is, in particular, true for text-based information, which is not supported by GTFS. ## Authentication Category: National journey planning. License: NLOD ## Format specification ### NeTEx and Norwegian profile NeTEx (Network and Timetable Exchange) is an XML-based format for sharing public transport data. It is a CEN-standard and is slated to become an EU standard for national datasets. - [Read about NeTEx](http://netex-cen.eu/) (external) - [Nordic NeTEx profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/728891481/Nordic+NeTEx+Profile) defines all the elements, and when and how to use them. - [White papers](http://netex-cen.eu/?page_id=14) (external) - [XSD XML Schema](https://github.com/NeTEx-CEN/NeTEx) (external) ### GTFS - [Reference](https://gtfs.org/documentation/schedule/reference/) (external) - [Best practice and tools](https://gtfs.org/) (external) ## Timetable Data All timetable datasets are continuously updated. When a data owner uploads new data, both the relevant regional dataset and the national dataset are automatically updated. **Note**: * GTFS basic does not use extended route types. ** Despite a number of counties being merged in 2020 the affected datasets continue to be delivered separately. - Whenever new data is uploaded by a data owner an update of the relevant dataset _and_ the national dataset is triggered. - Excessive downloading of files may lead to your IP being blocked. We expect that most users will have no need for more than one download per 24 hours. - Additionally, all datasets are automatically re-validated and re-exported every night where expired data is trimmed away, retaining data for a maximum of 48 hours back in time. The original creation date, and subsequently the date of the most recent change can be found by checking the `created` timestamp in `CompositeFrame`. For example: `created="2019-05-29T12:59:32.202"`. ## Status of NeTEx completeness from providers All Norwegian PTA's are sending native NeTEx from their planning system. The railway companies and some commercial PTO's are doing the same, while some are still developing this capability. The minor PTO's with only one or two lines are using AddTransit (GTFS) or the Entur-built tool Nplan (NeTEx). Planning systems in use by Entur customers capable of exporting Nordic NeTEx profile compliant data: - Hastus (by Giro) - DG BUSS (by DataGrafikk) - Optibus \* - Nplan (by Entur) \* - Trapeze for public transport (by Trapeze) - TrainPlan (by SignatureRail) - TurnIt \* in development --- ## Document: Stop Place Data Daily updated stop place data dumps for all public transport stops in Norway. URL: /open-data/stops # Stop Place Data import StopsTable from '../../src/runtime/components/open-data/StopsTable/StopsTable' import RegionalStopsTable from '../../src/runtime/components/open-data/RegionalStopsTable/RegionalStopsTable' import { Callout } from 'zudoku/components' This page lists all our stop place data dumps which are updated daily. All data dumps have permanent URL's and come as NeTEx or GTFS datasets. NeTEx is the official format for public transport data in Norway and is the most complete in terms of available data. GTFS is a downstream format with only a limited subset of the total data. ## Authentication Category: National journey planning. License: NLOD ## General information The stops referred to are defined in the [national stop registry](https://stoppested.entur.org/). It's possible to view the content without an account. You can also use the geocoder or NeTEx dump to extract what you may be looking for. The stop identifiers are unique across all the datasets. Regardless of the data source. The richness of the data depends on the source data from the respective county or operator. All parties are required to submit their data in the NeTEx format, in accordance with the Norwegian NeTEx profile, but unfortunately, we're not there yet. ## Format specification ### NeTEx and Norwegian profile NeTEx (Network and Timetable Exchange) is an XML-based format for sharing public transport data. It is a CEN-standard and is slated to become an EU standard for national datasets. - [Read about NeTEx](http://netex-cen.eu/) (external) - [Nordic NeTEx profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/728891481/Nordic+NeTEx+Profile) defines all the elements, and when and how to use them. - [White papers](http://netex-cen.eu/?page_id=14) (external) - [XSD XML Schema](https://github.com/NeTEx-CEN/NeTEx) (external) ### GTFS - [Reference](https://gtfs.org/documentation/schedule/reference/) (external) - [Best practice and tools](https://gtfs.org/) (external) ## Stop Place and Quays ### Complete datasets for Norway ### Stops and Quays per region – Current stops ### Railway Stations Datasets --- ## Document: Real-Time Data APIs for subscribing to real-time public transport data via SIRI and GTFS-RT feeds. URL: /open-data/realtime # Real-Time Data import { Callout } from 'zudoku/components' These APIs allow your server to subscribe to real-time data from all included real-time feeds in Norway on SIRI 2.0. It is available as SIRI XML, SIRI Lite (REST) and GTFS-RT. These services include only real-time data and not any basic journey planner information. If you are creating an end-user service such as a journey planner, the JourneyPlanner API is a better choice. ## Available data streams | Codespace | Source | SIRI ET | SIRI VM | SIRI SX | GTFS-RT Trip Updates | GTFS-RT Vehicle Positions | GTFS-RT Service Alerts | |-----------|--------|---------|---------|---------|---------------------|--------------------------|------------------------| | | Entire Norway | ✓ | ✓ | ✓ | | | | | AKT | Agder (AKT) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ATB | Trøndelag (AtB) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | AVI | Avinor | | | | | | | | BNR | SJ Nord (via Bane Nor) see FLT, GOA and VYG for other railway operators. | ✓ | | | | | | | BRA | Viken (Brakar) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | FIN | Troms og Finnmark (Snelandia) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | FLT | Flytoget | ✓ | | ✓ | ✓ | ✓ | ✓ | | GOA | Go-Ahead | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | INN | Innlandet (Innlandstrafikk) | ✓ | ✓ | ✓ | | | | | KOL | Rogaland (Kolumbus) | ✓ | ✓ | | ✓ | ✓ | | | MOR | Møre og Romsdal (Fram) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | NBU | Connect Bus Flybuss | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | NOR | Nordland fylkeskommune | ✓ | | ✓ | | | | | NSB | Vy | ✓ | ✓ | ✓ | | ✓ | | | OST | Viken (Østfold kollektivtrafikk) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | RUT | Oslo region (Ruter) | ✓ | | ✓ | ✓ | | ✓ | | SJN | SJ Nord | | | ✓ | | | | | SKY | Vestland (Skyss) | ✓ | ✓ | ✓ | | | | | SOF | Vestland (Kringom) | | | ✓ | | | | | TEL | Vestfold og Telemark (Farte) | | | | ✓ | ✓ | | | TRO | Troms og Finnmark (Troms fylkestrafikk) | ✓ | ✓ | ✓ | ✓ | ✓ | | | VKT | Vestfold og Telemark (VKT) | | | ✓ | | | | | VOT | Vestfold og Telemark | ✓ | ✓ | | ✓ | ✓ | | | VYB | Vy Buss (SE) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | VYG | Vy Group | ✓ | ✓ | ✓ | | ✓ | | | VYX | Vy Express | | ✓ | | | ✓ | ✓ | ## SIRI SIRI is a CEN Technical Standard that specifies a European interface standard for exchanging information about the planned, current or projected performance of real-time public transport operations between different computer systems. ### Publish/subscribe When using `publish/subscribe` you'll first get one (or more) set with initial data, and then continuous updates with changes. This option requires an accessible endpoint which accepts HTTP POST requests from the Entur SIRI service. ### Request/response For Request/Response, the `` attribute is used to track changes and must therefore remain the same for all subsequent requests in order to only get changes. The attribute `MoreData=true` means the data comes in bunches, just like paging, and more data can be fetched immediately after the first "page" is received. Eg. if there are 20,000 objects, these will be split up in smaller parts and repeated requests are needed to get the full set. ### Types of data #### ET – Estimated Timetable Real-time estimates for each service journey. Included are planned-, actual- and estimated departure times, cancellations and changes in stop patterns. #### VM – Vehicle Monitoring Vehicle-centric real-time data with the position of a vehicle, as well as any deviation from scheduled timetable on a given departure. #### SX – Situation Exchange Textual messages displayed to end users. They are always associated with a departure, line, stop etc., or combinations of these. ### SIRI Lite With simple HTTP GET calls to retrieve data, you can use the `requestorId` URL-parameter to _only_ retrieve changes made since the last time you asked. If you do not use this, you will always get the full dataset, not just the first time you make a request. You must use a unique [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier). - Example: https://api.entur.io/realtime/v1/rest/sx?requestorId=757c9284-0f12-4a46-a557-33a19e80119b ### More information - SIRI standard: https://transmodel-cen.eu/index.php/siri/ - Norwegian SIRI-profile: https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370420/Norwegian+SIRI+profile - Example SIRI-XML that follow the Norwegian SIRI-profile: https://github.com/entur/profile-norway-examples/tree/master/siri/ ## GTFS-RT GTFS Realtime is a feed specification that allows public transportation agencies to provide realtime updates about their fleet to application developers. It is an extension to GTFS (General Transit Feed Specification), an open data format for public transportation schedules and associated geographic information. ### Request/response Only supports request/response currently. Endpoints exist for each data type that download the full dataset, filtered by datasource (codespace) if provided. This dataset is updated every 15 seconds. Later we will support publish/subscribe and continuous updates. - Example: https://api.entur.io/realtime/v1/gtfs-rt/trip-updates?datasource=RUT ### Types of data #### Trip updates Delays, cancellations, changed routes. Similar to SIRI ET. #### Vehicle positions Information about the vehicles including location and congestion level. Similar to SIRI VM. #### Service alerts Stop moved, unforeseen events affecting a station, route or the entire network. Similar to SIRI SX. ### More information - GTFS-RT documentation: https://gtfs.org/documentation/realtime/reference/ - Trip updates example: https://gtfs.org/documentation/realtime/examples/trip-updates/ ## API Reference ### HTTP POST (Standard SIRI 2.0) Publish/subscribe: https://api.entur.io/realtime/v1/subscribe Request/Response: https://api.entur.io/realtime/v1/services Get data for only one operator, add `/` to the end of URL. You can find the operator's Codespace-ID in the list located above. Example: https://api.entur.io/realtime/v1/services/RUT ### HTTP GET (Standard SIRI 2.0 Lite) HTTP GET https://api.entur.io/realtime/v1/rest/sx HTTP GET https://api.entur.io/realtime/v1/rest/vm HTTP GET https://api.entur.io/realtime/v1/rest/et **Note:** Limited to 4 requests per minute. If more frequent updates are needed, publish/subscribe should be used. ### Optional HTTP-parameters #### datasetId - E.g. _datasetId=RUT_. You can find the operator's Codespace-ID in the list above. - Limits the results to original dataset-provider Example: https://api.entur.io/realtime/v1/rest/et?datasetId=RUT #### excludedDatasetIds - Comma-separated list of datasets to exclude from result - E.g. _excludedDatasetIds=RUT,NSB_ - Limits result by _excluding_ data from the provided datasetIds - _Note:_ Valid for VM and ET requests only (I.e. the opposite of parameter `datasetId`) Example: https://api.entur.io/realtime/v1/rest/et?excludedDatasetIds=BNR,OST,RUT #### useOriginalId By default we return data with IDs mapped to those used in the static route data. Instead, if you want the original IDs delivered from the underlying system, you can add a URL parameter useOriginalId = true. **NB:** This is also supported by SIRI Publish/subscribe and Request/Response Example: https://api.entur.io/realtime/v1/rest/sx?useOriginalId=true #### maxSize - E.g. _maxSize=10_ (default is 1500) - Limits the number of elements in the returned result. _requestorId_ will be used to track changes since last request and is provided in result. An id will be created and returned if not provided. - If more data exists, the attribute _MoreData_ will be set to _true_ Example: https://api.entur.io/realtime/v1/rest/et?maxSize=10 #### requestorId - E.g. _requestorId=757c9284-0f12-4a46-a557-33a19e80119b_ - Value needs to be unique for as long as only updated data are needed, a UUID should be used - First request creates a short lived session (timeout after e.g. 5 minutes) - Subsequent requests returns only changes since last request with the same requestorId Example: https://api.entur.io/realtime/v1/rest/sx?requestorId=757c9284-0f12-4a46-a557-33a19e80119b ### HTTP GET (GTFS-RT) HTTP GET https://api.entur.io/realtime/v1/gtfs-rt/trip-updates HTTP GET https://api.entur.io/realtime/v1/gtfs-rt/vehicle-positions HTTP GET https://api.entur.io/realtime/v1/gtfs-rt/alerts **Note:** Fetches complete dataset. Currently only updated every 15 seconds. #### datasource - E.g. _datasource=RUT_. You can find the operator's Codespace-ID in the list above. - Limits the results to original dataset-provider ## Additional Resources For more information on road status, incidents, public transport and schedules, visit [Transportportal.no](https://transportportal.no/en). The portal's data catalogue gives you descriptions and links to data sets and services with information on road status, incidents, public transport, schedules and much more. All data sets are open and available for re-use and as source for your own services. --- ## Document: Plan a Journey WIP URL: /guides/plan-a-journey # Plan a Journey :::note[Under Construction - Coming Soon] ::: --- ## Document: Administrating consents Administrate consent terms and store your customers' given consents URL: /guides/consents # Administrating consents ## Overview The consents API allows you to create and administrate terms for consent, and store your customers' given consents to these terms. ## Before you begin - Your client needs a partner access token to use this API, see the [authentication guide](/docs/authentication#partner-apis). - Your client needs to be assigned the role `Klientrolle - Samtykkeklient - Administrator`. ## Terminology - **Consent base**: contains the legal terms for consent, in all the languages you define. - **Consent**: connects your organisation to the consent base. - **Given consent**: The actual consent given by the customer. ## State handling and versioning Consent bases and consents have state handling, using the fields validFrom and validTo. The three different states are as follows: - **Draft**: If `validFrom` is not set or set to a time in the future. - **Active**: If `validFrom` is in the past and `validTo` is not set or set to a time in the future. - **Inactive**: If `validTo` is in the past Consent bases and consents can be updated as long as they’re in the draft state, using `PUT` endpoints. After they’re active, there are only a few fields that can be changed using the `PATCH` endpoints. Each consent base and consent have a version number. If you wish to do changes after the consent base or consent is active, you have to create a new version. Versions of the same entity cannot be active at the same time, so `validFrom` and `validTo` cannot overlap. ## Administrating consent terms See the [consents admin API](/apis/customers/consents-admin) for full documentation on how to administrate consent bases and consents ### Create a consent base When creating a new consent base, it requires a code unique within the system for later identification. The maximum length of this code is 20 characters, and we recommend that it includes the codespace for your organisation to avoid conflicts. E.g. use “ENT_INFO_SMS” for a consent base containing terms for receiving information about a journey on sms. To create a new consent base, use ::endpoint[consents/addConsentBase] The response from creating the consent base will contain a version number. Use the version number when updating the consent base later and when creating consents. ### Create consent After you’ve created your consent base, you need to create the consent. This requires the consent code and the version number of the consent base you just created. ::endpoint[consents/addConsent] ### Updating consent base Consent bases are versioned. If you want to update the terms for a consent base when it is active, you have to create a new version. The `validTo` and `validFrom` for two versions of a consent base cannot overlap. After you’ve created a new version of a consent base, you need to create a new consent and collect new given consents from the customers. Create a new version of the consent base using following endpoint: ::endpoint[consents/createNewVersionOfConsentBase] ## Collect given consents from customers When consents have been created for you organisation and the consents are active, you can start collecting given consents from customers in your client. See [the consents client API](/apis/customers/consents-client) for documentation on how display consent terms and collect given consents --- ## Document: Getting started A step-by-step guide to start using Entur's APIs and developer tools. URL: /docs/getting-started # Getting started import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "zudoku/ui/Card"; import { Button } from "zudoku/ui/Button"; import { Badge } from "zudoku/ui/Badge"; import { Link } from "zudoku/components"; import { ArrowRight, ShieldCheckIcon } from "zudoku/icons"; :::lead Entur's APIs give developers and partners access to Norway's public transport infrastructure — from open journey planning data to commercial ticket sales integrations. Follow the steps below to get set up. ::: ---

Step 1

## What do you want to build with Entur
Depending on your use case, you can use open services, partner services, or combine both.
Public transport data APIs Available to everyone. No partnership agreement required.
  • Journey planner
  • Mobility (microtransports, bysykkel..)
  • Real-time vehicle positions
  • Stops and infrastructure data

Access requirements

  • Client identification (ET-Client-Name)
Sales, ticketing & operator APIs For organisations with a partnership agreement with Entur.
  • Ticket sales and order management
  • Timetable and deviations
  • Seating and inventory
  • Customers and personalisation

Access requirements

  • Partnership agreement with Entur
  • Client identification (ET-Client-Name)
  • OAuth 2.0 authentication
:::info[Need to become an Entur partner?] Partner services require a signed agreement with Entur. If your organisation doesn't have one yet, find out how to get started. [How to become an Entur partner →](https://entur.no/partner) :::

---

Step 2

## Client identification (ET-Client-Name)
Every Entur API — open and partner — requires your application to identify itself using the `ET-Client-Name` header. This is always the first step, regardless of which service type you are using. This helps Entur understand how its APIs are used and allows traffic to be managed responsibly. Requests without this header may be rate limited or blocked. Use a value that uniquely identifies your company and application, in the form `-` (lowercase, no spaces). ### Example If your company is "Forsen Utvikling" and your app is "Infoplakat", your `ET-Client-Name` would be `forsen_utvikling-infoplakat`. ```sh curl --request GET \ --url "https://api.entur.io/distance/stop-place-distances/NSR:StopPlace:337/NSR:StopPlace:1" \ --header "ET-Client-Name: forsen_utvikling-infoplakat" ```

---

Step 3

## Authentication
If you are only using **Open services**, skip to [step 4](#first-api-call). Partner APIs require OAuth 2.0 Client Credentials authentication in addition to client identification. See the full guide for setup steps, code examples, environments, and troubleshooting.
---

Step 4

## First API call
Try the Geocoder API, as it is open and does not require authentication. This call looks up a stop place by its national ID and returns its name and coordinates. ```sh curl "https://api.entur.io/geocoder/v1/place?ids=NSR:StopPlace:337&lang=no" \ -H "ET-Client-Name: my_company-my_app" ``` --- ## Using our docs with AI tools Every page in the developer portal has a **Copy page** dropdown in the top right corner. Use it to copy the page as Markdown, open it directly in Claude or ChatGPT, or share the link. Doing so on this page is a good starting point for any LLM. For programmatic access (e.g. adding to `CLAUDE.md` or `AGENTS.md`), we expose: - [`/llms.txt`](https://beta.developer.entur.no/llms.txt) — the best starting point for any LLM; an index of all doc pages with links to individual Markdown files - [`/llms-full.txt`](https://beta.developer.entur.no/llms-full.txt) — all documentation in a single file - Any page as Markdown — append `.md` to its URL (e.g. `/docs/authentication.md`) --- ## Next steps Now that you are set up, explore the resources below.

Services

Open Services | Partner Services
Explore what you can build with open and partner services.

How-to guides

Guides Step-by-step instructions for achieving specific integration goals.

Understanding

Concepts The ideas and standards behind Entur's ecosystem.

Reference

API catalogue Browse all Entur APIs with full endpoint and parameter reference.
--- ## Document: Authentication Partner APIs require OAuth 2.0 client credentials authentication in addition to client identification. This guide covers setup steps, code examples, environments, and troubleshooting. URL: /docs/authentication # Authentication Partner APIs require [OAuth2](https://oauth.net/) client credentials. You authenticate by exchanging a Client ID and Secret for a short-lived JWT access token, then sending that token in the `Authorization` header. :::note All Entur APIs, open and partner, also require the `ET-Client-Name` header on every request. See [**Client identification**](/docs/getting-started#client-identification-et-client-name). ::: ## Setup ### 1. Create client credentials 1. Go to [Entur Partner](https://entur-partner.entur.org/permission-admin/clients/create) and create a client 2. View the created client and note the **Client ID** and **Client secret** 2. Be sure to store the **Client secret** securely. :::note Only users with the role [**Brukeradministrator**](https://entur-partner.entur.org/permission-admin/roles/view/35) in your organization can create clients. ::: ### 2. Get an access token Call the authentication service that matches the environment where your client was created. Use the `client_credentials` grant type. | Environment | Authentication service endpoint | Audience | |-------------|-----------------------------------|------------------------------| | Production | https://partner.entur.org | https://api.entur.io | | Staging | https://partner.staging.entur.org | https://api.staging.entur.io | | Dev | https://partner.dev.entur.org | https://api.dev.entur.io | **Request body** ```json { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "audience": "https://api.entur.io", "grant_type": "client_credentials" } ``` **Example request (production)** ```sh curl --request POST \ --url https://partner.entur.org/oauth/token \ --header 'content-type: application/json' \ --data '{ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "audience": "https://api.entur.io", "grant_type": "client_credentials" }' ``` We recommend using established [OAuth2 libraries](https://oauth.net/code/) instead of building this flow from scratch. ### 3. Use the access token Include the JWT access token in the `Authorization` header for every Partner API request: ```http Authorization: Bearer ``` **Example request** ```sh curl --request GET \ --url "https://api.entur.io/personalisation/v1/programs/1" \ --header "Authorization: Bearer " ``` ### 4. Cache and expiry - Cache access tokens securely and reuse them until they expire. - Tokens from Entur’s authentication service are valid for **24 hours**. - You can track expiry via the `expires_in` field from the token response or the `exp` claim inside the JWT. Requests using expired tokens will return HTTP 401. ## Troubleshooting Common HTTP status codes during authentication: - **401 Unauthorized** – Missing/invalid `client_secret`, missing token, or expired token. - **403 Forbidden** – The token is valid, but lacks required permissions for the endpoint. - **408 Session timeout** – The token expired during processing; obtain a new token. --- ## Document: Partner APIs Browse and explore Entur's partner APIs. URL: /apis/partner # Partner APIs import { apis } from "../../src/common/apis"; --- ## Document: Open APIs Browse and explore Entur's open APIs. URL: /apis/open # Open APIs import { apis } from "../../src/common/apis"; --- ## Document: API Specifications Complete list of all Entur OpenAPI and GraphQL API specifications with download URLs. URL: /apis/api-specs # API Specifications This page lists all available API specifications. REST APIs provide OpenAPI (JSON) specs. GraphQL APIs provide introspection endpoints. ## Open REST APIs These APIs are publicly available. Requests must include the `ET-Client-Name` header. | API | Description | OpenAPI spec | |-----|-------------|-------------| | Distances and zones | Calculates distances between Stop Places | [schema.json](/apis/prdudisapi/latest/schema.json) | | Geocoder v1/v2 (deprecated) | Geocoding and reverse geocoding for Norwegian addresses and points of interest. | [schema.json](/apis/geocoder-v2/latest/schema.json) | | Geocoder v3 | Geocoding and reverse geocoding for Norwegian addresses and points of interest. | [schema.json](/apis/geocoder/latest/schema.json) | | Stop Place Register | The Stop Place Register provides access to public transportation infrastructure data across Norway, including stop places, quays, parkings, and related NeTEx entities. This API enables developers to query stop place information with details on location, accessibility features, transport modes, fare zones, and hierarchical relationships. Ideal for journey planning applications, transportation analysis, mobility services, and public transit integrations. | [schema.json](/apis/stop-place-v1-read/latest/schema.json) | | Timetable Import Info | API for checking the status of timetable data imports. | [schema.json](/apis/timetable-import-info/latest/schema.json) | ## Open GraphQL APIs These APIs use GraphQL. Use introspection queries or see the linked documentation for schema details. | API | Description | Documentation | |-----|-------------|---------------| | Journey Planner | This API is the core service for journey planning and uses OpenTripPlanner software to provide departure boards for individual stops, and point-to-point journey planning for all public transport in Norway, including real-time information, regardless of transport mode, or operator. All data is presented as a Transmodel-based GraphQL-API. | [docs](/docs/open-services/journey-planner) | | Mobility | The Mobility API is an aggregation service for shared mobility data in Norway. It provides access to real-time information about shared bikes, e-scooters, and other mobility services from multiple operators across Norwegian cities. | [docs](/docs/open-services/mobility) | | Vehicle Positions | The Vehicle Positions API is a GraphQL service that provides real-time positions and status for public transport vehicles across Norway. It enables fetching and streaming live vehicle data including location, delays, occupancy, and journey information. | [docs](/docs/open-services/vehicle-positions) | ## Partner REST APIs These APIs require OAuth2 authentication. See [authentication](/docs/authentication#partner-apis) for details. | API | Description | OpenAPI spec | |-----|-------------|-------------| | Clearing | Partner API documentation for self serviced use of the Clearing services. See the developer guide for more information. | [schema.json](/apis/clearing/latest/schema.json) | | Consents API | An API for handling consents within Entur's sales systems | [schema.json](/apis/consents/latest/schema.json) | | Customers API | Documentation of the Customers API | [schema.json](/apis/customers/latest/schema.json) | | Offers V3 beta | This api is in Beta. Search for offers by different means. | [schema.json](/apis/offers-partner/latest/schema.json) | | OMSA | Open Mobility Sales API for searching, selecting, and purchasing mobility products and related resources. | [schema.json](/apis/omsa/latest/schema.json) | | Order Notes | Repository for data that is connectable to `orderId` and can be represented in String form. Note that only one note per `type` is able to be used per `orderId` for DEADLINE, VENDOR_CONTACT_INFO_OVERRIDE, ZERO_TICKET and PENALTY_FARE. If there is any need for nested data structures, consumers are invited to simply store small JSON objects in the `text` field. | [schema.json](/apis/order-note-partner/latest/schema.json) | | Orders | The Order API provides services to create and manage orders in Entur sales platform. It allows clients to create orders, add and change order lines, apply fees, manage connected reservations, and handle traveller information. | [schema.json](/apis/order-partner/latest/schema.json) | | Payments | The Payments API acts as a gateway to external payment service providers and provides endpoints to create, process and credit payment transactions. | [schema.json](/apis/payment-partner/latest/schema.json) | | Personalisation Client Integration | Integrate personalisation in clients, for example show a customers status in programs. | [schema.json](/apis/personalisation-client/latest/schema.json) | | Personalisation Privacy | Retrieve privacy data from personalisation to ensure GDPR compliance. | [schema.json](/apis/personalisation-privacy/latest/schema.json) | | Personnel tickets | Personnel tickets are a Norwegian railway discount scheme providing reduced fares for employees, pensioners, and eligible family members in participating companies. The scheme is owned by the Norwegian Railway Directorate and managed by Entur, requiring companies to enter an agreement to participate. This API supports managing employee eligibility, connecting user profiles to ticket rights, and applying those rights in ticket sales. It also enables reporting of personnel ticket usage for administrative and tax purposes. | [schema.json](/apis/personnel-tickets/latest/schema.json) | | Products | This API provides services to read and maintain products and fare data for public transport in Norway. | [schema.json](/apis/products/latest/schema.json) | | Products (Draft) | **This API specification is a draft and is not yet implemented. Endpoints, schemas, and | [schema.json](/apis/products-api/latest/schema.json) | | Raw Timetable Data | Provide access to the original NeTEx datasets uploaded by data providers | [schema.json](/apis/raw-timetable-data/latest/schema.json) | | Receipt Partner | Public API for generating and delivering receipts for customer orders. Provides endpoints to send receipts, determine the resulting receipt type for an order, and retrieve pickup-code messages in multiple formats and languages. | [schema.json](/apis/receipt-partner/latest/schema.json) | | Refunds | Check refundable options and perform refunds or compensations on customer orders. This API allows partners to preview refund outcomes, execute refunds, and apply price reductions when compensation is sufficient. | [schema.json](/apis/refund-partner/latest/schema.json) | | Reserve Offers | Simplify adding offers to an order | [schema.json](/apis/reserve-offers-partner/latest/schema.json) | | Third Party Product - Partner | Third party product is a catalog for products that does not exist in Enturs standard product database. | [schema.json](/apis/third-party-product-partner/latest/schema.json) | | Ticket Distributions | Easy way to manage and distribute new tickets to ticketing systems. | [schema.json](/apis/ticket-distribution-partner/latest/schema.json) | | Timetable Management | Entur provides an API for uploading and downloading NeTEx timetable datasets. | [schema.json](/apis/timetable-management/latest/schema.json) | --- ## Document: How to fetch tax savings reports How to fetch reports of tax savings for employees in the personnel ticket system. URL: /guides/personnel-ticket/5-fetching-reports # How to fetch tax savings reports ## Overview This guide explains how to fetch reports of tax savings for employees in the personnel ticket system. Reports of taxable amounts for the previous month are automatically calculated on the first day of each month. The monthly tax reports must be retrieved and reported to the tax authorities by the employer. ## Fetching a tax savings report To fetch a report of tax savings, use ::endpoint[personnel-tickets/getTaxSavingsReportAsCsvFile] It fetches a tax savings report for a given company, month and year. It accepts the following query parameters: | Param Name | Required | Type | Description | Default | |------------|----------|---------|-----------------------------------------------------------------------------------------------------------------------------------|---------------| | companyId | Yes | integer | Internal company ID in the personnel ticket system. This is different from your organisations ID in Enturs organisation registry. | | | year | No | integer | Year from 2021 | Current year | | month | No | string | Month (1–12) | Current month | --- ## Responses - 200 OK **Example CSV Response** ```csv companyId,employeeNo,ssn,saving,fromDate,toDate,employeeStatus 3,1234,14104512345,230.00,2020-02-01,2020-02-29,P 3,1233,23047854321,1102.00,2020-02-01,2020-02-29,A ``` - 404 Not Found - No report exists for the given parameters --- ## Field descriptions | Field | Format | Meaning | Comment | |----------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------| | companyId | int | Internal company ID in the personnel ticket system. This is different from your organisations ID in Enturs organisation registry. | Useful for clients with multiple companies | | employeeNo | string | Employee number provided by company | May be reused; can be negative or 0 for pensioners | | ssn | string (11 digits) | Social security number | | | saving | string (xxxxx.xx) | Savings for the given month | Refunds are included, so may be a negative number | | fromDate | ISO string (yyyy-MM-dd) | First date in report (inclusive) | | | toDate | ISO string (yyyy-MM-dd) | Last date in report (inclusive) | | | employeeStatus | "P", "A", or "E" | Pensioner, Active employee or Bereaved (Etterlatt) | The value is based on termination code | --- ## Document: How to use personnel ticket rights in the sales process A guide on how to implement personnel ticket rights in the sales process. URL: /guides/personnel-ticket/4-using-personnel-ticket-rights # How to use personnel ticket rights in the sales process ## Overview This guide explains how to implement personnel ticket rights in your client, enabling the purchase of personnel tickets. To use personnel ticket in the sales flow: * The customer must have a private profile in Entur Customers * The customer must be connected to ticket rights through their profile (See guide: [How to connect profiles with personnel ticket rights](/guides/personnel-ticket/3-connecting-user-profiles)) --- ## Summary flow 1. Get existing ticket rights 2. Let user select ticket rights 3. Request discounted offers 4. Validate eligibility 5. Complete payment 6. Register usage and tax reporting --- ## 1. Get existing ticket rights To fetch the ticket rights for a customer number, use ::endpoint[personnel-tickets/getEntitlementsByCustomerNumber] ### Notes * Every employee has two **ticket rights**: - One for private travel - One for work travel * Family members and pensioners have one personnel ticket right for private travel --- ## 2. Present ticket rights to the user The sales client should: - Display relevant ticket rights to the user - Allow the user to choose which rights to use - Map each ticket right to a traveller type (e.g. `ADULT`, `CHILD`, `STUDENT`, `SENIOR`) ### Filtering The available options should be filtered based on: - Travel date - Contract validity period You also need to determine whether any travellers qualify for senior, child or student. These categories may be determined by your system if the traveler age is known. --- ## 3. Use selected ticket rights to get discounted offers After the user selects ticket rights: - Call ::endpoint[reserve-offers-partner/reserveOffers] - Include the selected entitlement product IDs in the request - The response from the API will include discounted prices based on the personnel ticket rights Here is how to include the entitlement product IDs in the request body: ``` { ... "travellers": [ { ... "customerId": "1234567", "productIds": [ "ENT:EntitlementProduct:PersonnelTicket" ] } ] } ``` --- ## 4. Validate before payment Before proceeding to payment, validate the offer against personnel ticket rules ⚠️ If validation is skipped, the _purchase_ may succeed, but _ticket issuance_ may fail due to validation errors. This can lead to a poor user experience, as the customer may pay for a ticket that cannot be issued. To validate, use ::endpoint[personnel-tickets/validateContractUse] --- ## 5. Complete payment Proceed to payment as usual. Once the ticket is distributed: - Personnel ticket usage will be registered in the system - The taxable benefit will be recorded for tax reporting purposes --- ## Next steps Guide: [Fetching tax savings reports](/guides/personnel-ticket/5-fetching-reports) --- ## Document: How to connect user profiles with personnel ticket rights How to connect customer profiles with personnel ticket rights. URL: /guides/personnel-ticket/3-connecting-user-profiles # How to connect user profiles with personnel ticket rights ## Overview This guide explains how to connect personnel ticket rights to customer profiles. --- ## Before you begin For each customer profile you want to connect to a personnel ticket right, you will need: * The `customerNumber` for the customer's private profile * The customer’s personal pickup code. The pickup code is a unique code that identifies the customer in the personnel ticket system and is used to connect the customer's profile to their ticket rights. You can obtain the pickup code for a customer by calling ::endpoint[personnel-tickets/findTicketRightsHolders] and reading the `ticketHolderCode` field in the response. --- ## Connecting profiles to personnel ticket rights A personnel ticket right in the personnel ticket system has as a **validity period**. * Validity periods **cannot extend into a new calendar year**. * Contracts are **automatically renewed yearly** in the personnel ticket system. To connect a customer affiliated with your organisation to a personnel ticket right, use ::endpoint[personnel-tickets/claimPersonnelTicket] This endpoint will: * Look up the customer based on `customerNumber` * Connect the customer to a ticket right (contract) matching the pickup code (`externalReference`) --- ## Next steps * Guide: [How to use personnel ticket rights in the sales process](/guides/personnel-ticket/4-using-personnel-ticket-rights) --- ## Document: How to Import Employees in CSV Format This guide explains how to import employees into the personnel ticket system using a specific CSV format. URL: /guides/personnel-ticket/2-importing-employees-in-csv-format # How to Import Employees in CSV Format ## Overview This guide explains how to import employees from an external system into the personnel ticket system using a specific CSV format. The CSV file may also include **pensioners** who are eligible for personnel ticket rights. --- ## Before you start To use this guide, you need to: * Have your employee list available as a CSV file --- ## The CSV format | Field Name | Notes | Default Value | |--------------------------|-----------------------------------------------------------------------------------------------------------------------------------|---------------| | employeeNo | Your internal employee number for this employee. | | | companyId | Internal company ID in the personnel ticket system. This is different from your organisations ID in Enturs organisation registry. | | | employmentTypeId | The type of employment. See Employment Types below. | | | dateOfBirth | In format "yyyy-MM-dd": "1974-11-23" | | | ssn | 5-digit ssn | | | firstName | First name of employee | | | surname | Surname of employee | | | addressLine | Street address of employee | | | postalCode | Postal code of employee | | | abstainFromTicket | Whether this employee has opted out. Valid values are true and false | false | | hireStartDate | Date of hire. Format "yyyy-MM-dd", "1974-11-23" | | | payType | The pay category. See [Pay types](#pay-types) below. | | | hireEndDate | The day the employee no longer works for the company. Format "yyyy-MM-dd", "1974-11-23" | "" | | hireEndCause | The reason for end of hire. See [End Causes](#end-causes) below. | "" | | disabilityGrade | The percent disability. Sensitive personal data. Number from 0 to 100. | 0 | | disabilityFromDate | The day the disability is valid. Required if disabilityGrade > 0 | "" | | employmentPercentage | Degree of employment. Number from 0 to 100. | | | employmentPercentageDate | Date the employment percentage is valid. Format "yyyy-MM-dd", "1974-11-23". | "" | | paidPercentage | Percentage of pay. | | | leaveFromDate | If employee is on leave. Format "yyyy-MM-dd", "1974-11-23". | "" | | isDeleted | Whether employee is deleted in the pesonnel ticket system. | false | Fields without a default value are required. A header row is not required, but the fields must be in the order specified in the table. ### Employment types | Id | Norwegian Notes | |----|--------------------------------| | F | Fast ansatt i stilling | | M | Midlertidig tilsatt i stilling | | T | Tilkallingsvikar/sesong | | U | Ukjent tjenesteforhold | ### Categories | Code | Value | |------|---------------| | 1 | bronze ticket | | 2 | silver ticket | ### Pay types | Id | Norwegian Notes | |----|------------------------------------| | 1 | Ukjent | | A | Aktiv stilling | | D | Delvis omsorgspermisjon | | E | Red. arbeidstid etter AML 46A | | F | Fødselspermisjon | | L | Lånt ut til annen enhet | | M | Permisjon for militær/siviltj | | N | Permisjon for annen stilling i NSB | | O | Omsorgspermisjon uten lønn | | P | Militær/siviltjeneste uten lønn | | R | Studiepermisjon uten lønn | | S | Studiepermisjon m/lønn | | T | Tjenestegjøring i høyere stilling | | U | Permisjon m/uførepensjon | | V | Delvis uførepermisjon | | W | Delvis overgang til AFP | | X | Permisjon, annet u/lønn | ### End causes | Code | Norwegian Notes | |------|-----------------------------------------------| | A | Overgang alderspensjon (kode 341) | | B | Slutt v/overg til AS (kode 350) | | D | Dødsfall (aksjonskode 320) | | E | Egen oppsigelse (kode 310+330) | | F | Overgang AFP/FTP (kode 349) | | I | Oppsagt v/innskr. (kode 352) | | M | Mangler årsaksangivelse | | O | Slutt l/opplæring (kode 353) | | S | Særaldersgrense (kode 345) | | T | Dødsfall, tjenesteulykke (kode 321) | | U | Uførepensjon/Oppsigelse ved sykdom (kode 361) | | V | Slutt 6 mnd lønn (kode 354) | | X | Slutt annen årsak (kode 350) | | Y | Ventelønn 30 års tjeneste | | Z | Avskjed (kode 351) | --- ## Importing employees For importing employees, use ::endpoint[personnel-tickets/importMultipleEmployeesCsv] ### Request body ```json { "importFile": "importFileName" } ``` --- ## Response and behavior A list of **actually changed employees** is returned. The list may be empty if all uploaded employees already exist with the identical values The personnel ticket system calculates whether an employee is entitled to a personnel ticket and create the necessary ticket rights in the internal Entur systems for the users. ### Validation * If **any birth date or SSN is invalid**: * ❌ Nothing will be imported * ❌ An error message will be returned * The error will include: * Invalid birth dates * Invalid SSNs --- ## Next steps Guide: [How to Connect Profiles with Personnel Ticket Rights](/guides/personnel-ticket/3-connecting-user-profiles) --- ## Document: How to add and administrate employees through the Personnel Ticket API This guide is intended for partners who want to integrate their own HR or employee management systems with the personnel ticket system. URL: /guides/personnel-ticket/1-add-and-administrate-employees # How to add and administrate employees through the Personnel Ticket API ## Overview This guide explains how to add and manage employees through the Personnel Ticket API. It is intended for partners who want to integrate their own HR or employee management systems with the personnel ticket system. The personnel ticket system determines employee eligibility for personnel ticket rights based on registered employee data. The data you import through the API is used to automatically manage ticket rights for employees, so it is important to keep the information up to date. Employee data is handled in two stages: **1. Import stage:** When you import employee data via the API, an employee import record is created. This represents the data you have submitted, but it is not yet active in the personnel ticket system. **2. Processing stage:** A scheduled background job processes employee imports and transfers them to the main employee register. Once processed, the employee becomes an active employee and is used for ticket eligibility and other operations. The background job runs every 10 minutes, so there may be a delay between importing an employee and it being available in the system. Because of this asynchronous flow, changes are not applied immediately. After creating or updating an employee import, it may take a few minutes before the employee appears in the system and can be used in other API operations. ## The Employee Import API allows you to ### 1. Import a new employee Create an employee import record to submit a new employee to the system. ::endpoint[personnel-tickets/importNewEmployee] Use the Employee Import API to send the employee data. The response includes an ID that identifies the import record. This ID may be used for updating or retrieving the import before it has been processed. ### 2. Import multiple employees using CSV You can import multiple employees in a single request by uploading a CSV file. :endpoint[personnel-tickets/importMultipleEmployeesCsv] Each employee in the response will include an ID identifying its import record, which can be used for follow-up operations. For details on the CSV format and request structure, see: [Import employees via CSV](/guides/personnel-ticket/2-importing-employees-in-csv-format) ### 3. Update an imported employee You can update an employee before it has been processed by modifying its import record. Use the importedEmployeeId (the import ID returned during creation) to update the data. ::endpoint[personnel-tickets/patchImportedEmployee] ### 4. Retrieve an imported employee You can retrieve the data of an imported employee record using its import ID. ::endpoint[personnel-tickets/getImportedEmployee] ### 5. Retrieve an employee To retrieve an employee in the employee registry, you need to search using the national identification number. You may also search by `employeeNo`, but this is not guaranteed by the system to be unique within an organisation. If successful, the response will include the internal employee ID. This ID can be used for follow-up operations such as setting the yearly fee status or registering disability proof status. ::endpoint[personnel-tickets/findEmployees] ### 6. Set the yearly fee status for an employee Once an employee has been processed and is available in the employee registry, you can set the yearly fee status. This operation uses the internal employee ID (not the import ID). ::endpoint[personnel-tickets/setYearlyFee] ### 7. Register disability proof status for an employee You can register disability proof status for an employee for a given year. This operation also requires the internal employee ID (not the import ID). ::endpoint[personnel-tickets/setDisabilityProof] ## Next steps Guide: [How to Connect Profiles with Personnel Ticket Rights](/guides/personnel-ticket/3-connecting-user-profiles) --- ## Document: Search offers How to get your first OMSA offer. URL: /guides/omsa/search-offers # Search offers import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "zudoku/ui/Accordion"; This guide gets you from zero to your first OMSA :def[omsa-offer|offer]. You will: - Model who is travelling. - Send your first `search-offers` process request. - Understand the basics of an OMSA `OfferCollection` response. :::note Eager to start experimenting with code? Explore the API spec directly at `https://api.dev.entur.io/omsa/v1/api` (does not require auth). ::: ## Before you begin To use this guide, you need to: - Be an authorised Entur partner. - Have OAuth2 client credentials (`client_id` and `client_secret`). - Have header values for :def[Entur-Distribution-Channel] and :def[Entur-POS]. - Use the OMSA dev base URL `https://api.dev.entur.io/omsa/v1`. :::info Read more about authentication [here](/docs/authentication#partner-apis). ::: ## 1. Specify who is travelling When searching for offers, OMSA supports two traveller models: - `individual_traveller`: an identifiable traveller (with specific attributes such as age, name, and possibly other personal details). - `user_profile`: an anonymous traveller profile with a count. You can use one of them, or both in the same request. ```json { "travellers": [ { "type": "individual_traveller", "id": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8", "age": 30 } ], "profiles": [ { "type": "user_profile", "id": "1c9b2b5a-f291-404b-8235-50641ef2b733", "ageGroup": "ADULT", "count": 1 } ] } ``` ## 2. Search for your first offer Send your first request to `https://api.dev.entur.io/omsa/v1/processes/search-offers/execute`. OMSA supports several place models in `specification`, most commonly: - Fare zones (`KOL:FareZone:*`) - Stop places (`NSR:StopPlace:*`) - GPS coordinates (`GPS:lat,long[,alt]`) :::info These place references are used throughout the Entur platform and are based on :def[NeTEx] concepts. Read about the :def[FareZone] and :def[StopPlace] concepts, or see all accepted formats for OMSA :def[omsa-place-id|Place ID]. ::: Example request (FareZone to FareZone) ```bash --header "Authorization: Bearer " \ --header "Accept-Language: en-GB" \ --header "Content-Type: application/json" \ --header "Entur-Distribution-Channel: ORG:DistributionChannel:App" \ --header "Entur-POS: ORG-Web" \ ``` ```json { "inputs": { "type": "search_offer", "specification": { "from": { "placeId": "ORG:FareZone:1" }, "to": { "placeId": "ORG:FareZone:3" } }, "travellers": [ { "id": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8", "type": "individual_traveller", "fullName": "Ola Nordmann", "age": 30 } ] } } ``` Example request (StopPlace to StopPlace with profile) ```bash --header "Authorization: Bearer " \ --header "Accept-Language: en-GB" \ --header "Content-Type: application/json" \ --header "Entur-Distribution-Channel: ORG:DistributionChannel:App" \ --header "Entur-POS: ORG-Web" \ ``` ```json { "inputs": { "type": "search_offer", "timestamp": "2026-04-24T09:00:00+02:00", "specification": { "from": { "placeId": "NSR:StopPlace:28434" }, "to": { "placeId": "NSR:StopPlace:61291" }, "startTime": "2026-04-24T10:00:00+02:00", "endTime": "2026-04-24T11:00:00+02:00" }, "travellers": [ { "type": "individual_traveller", "id": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8", "fullName": "Ola Nordmann", "age": 30 } ], "profiles": [ { "type": "user_profile", "id": "1c9b2b5a-f291-404b-8235-50641ef2b733", "ageGroup": "ADULT", "count": 1 } ] } } ``` :::note Please use `FareZone` in your application. Entur still supports the alternative spelling `TariffZone`, but note that this spelling is deprecated. ::: ## 3. Understand the response Confirm that: - The request returns HTTP `200`. - The response contains at least one :def[omsa-offer|offer]. - Returned offers match expected :def[omsa-place-id|place ID]s and traveller inputs. ### Example response ```json { "type": "OfferCollection", "offers": [ { "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b", "type": "offer", "properties": { "legs": [ { "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b", "type": "leg", "sequenceNumber": 1, "traveller": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8", "state": "NOT_STARTED", "price": { "amount": 354.0, "currencyCode": "NOK" }, "products": [ "KOL:PreassignedFareProduct:4e913d65" ] } ], "products": [ { "type": "product", "productId": { "productId": "KOL:PreassignedFareProduct:4e913d65", "name": "Kolumbus 7-day ticket" }, "productName": "Kolumbus 7-day ticket" } ], "price": { "amount": 354.0, "currencyCode": "NOK" } } } ] } ``` OMSA returns offers with `Leg` objects, even for simple `Zone`-`Zone` or `StopPlace`-`StopPlace` searches. In these cases, the leg represents a single traveller on a single product. To see which traveller belongs to which product and price, check the legs. :::warning If requests fail with `401` or `403`, verify token scopes and header values before retrying. ::: ### Troubleshooting tips - If you receive an empty `offers` array, check that your `specification` parameters (place IDs, time range) align with available data in the dev environment. - Use the OMSA API spec and error messages to debug issues. Common errors include invalid place IDs, duplicate traveller IDs, or missing required fields and headers. - For authentication issues, ensure your OAuth2 token is valid and has the necessary scopes for OMSA access and the distribution channel and POS you are using. - If you encounter unexpected errors or need further assistance, contact Entur support with details of your request and response for help. Include the `X-Correlation-ID` from your response headers to help us trace the problematic requests. # Next steps - Select and purchase an offer using the `select-offer` and `purchase-package` process endpoints (link coming soon). - Apply discounts for eligible travellers with `entitlements`, e.g. seniors or students (link coming soon). - Advanced `search-offers` requests, e.g. with a `TripPattern` from the Entur Journey Planner or a group of travellers (link coming soon). --- ## Document: Generic Settlements How generic settlements are used to clear financial transactions between operators and Entur. URL: /guides/clearing/generic-settlements # Generic Settlements ## About Generic Settlements A Generic Settlement is a data structure used to clear financial transactions between financially relevant parties. It's a flexible, extensible structure for representing settlement data in a standardized format that can be process directly, eliminating the need for custom integration modules. The settlement also documents the resulting General Ledger entries. Settlements are processed atomically — they either succeed completely or fail entirely, ensuring data integrity. The Clearing system supports several settlement variants, but each requires custom mapping logic to transform external data into clearing-compatible structures. The mapping logic needs to be configured by Entur before the settlements is submitted. This document focuses on submitting Generic Settlements as supported by the Clearing API. :::note Settlement clearing is a complex topic requiring solid understanding of accounting principles, VAT regulations, business requirements, and configuration of the Clearing system. This guide enables developers to submit Generic Settlements but does not cover the full scope of settlement clearing. Developers must collaborate closely with the Chart of Accounts administrator to ensure proper modelling of the data to be cleared. ::: ## Settlement Structure A Settlement can model any type of financial transaction data, not limited to fare product sales. Relevant use cases include: * Cash Deposit transactions * Settlement corrections * Payment provider reconciliation * Third-party marketplace transactions * Revenue sharing agreements * Sales commission calculations The structure is designed to support wide number of clearing mechanisms, with extensibility for future requirements. The following diagram illustrates the hierarchical structure of a Settlement: ```mermaid graph TD A[Settlement
Point Of Sale: POS:OsloS
Settlement Number: 3
Distribution Channel Id: DCI:App] A --> B1[Transaction
type: SALES] A --> B2[Transaction
type: PAYMENT] A --> B3[Transaction
type: ...] B1 --> C1[Annex
...] B1 --> C2[Annex
ID: SalesPackage:123
attributes:
keyB=valueB
context: keyF=valueF] C2 --> D1[Parameter
ID: Discount:Child
attributes:
keyC=valueC] C2 --> C3[Annex
ID: Product:345
attributes:
keyD=valueD
context: keyG=valueG] C2 --> D2[Annex
ID: Product:456
attributes:
keyE=valueE] C2 --> D3[Annex
...] C3 --> D4[Annex
...] B2 --> C4[Annex
...] classDef settlStyle fill:#e1f5ff,stroke:#333,stroke-width:2px, color:#000 classDef transStyle fill:#ffffff,stroke:#333,stroke-width:2px, color:#000 classDef annexStyle fill:#fff2cc,stroke:#333,stroke-width:2px, color:#000 classDef paramStyle fill:#d9ead3,stroke:#333,stroke-width:2px, color:#000 class A settlStyle class B1,B2,B3 transStyle class C1,C2,C3,C4,D2,D3,D4 annexStyle class D1 paramStyle ``` ### Structure Overview Settlements consist of hierarchical elements — Transactions, Annexes, and Parameters — each with unique identifiers and attributes that provide additional context for clearing and reporting. The "Generic" designation reflects the structure's ability to model any type of settlement data, not just fare products. This flexibility enables the Clearing system to process diverse financial scenarios through a standardized format. ```mermaid classDiagram direction TB class PersistedSettlement { String posRef String distributionChannelRef String settlementNumber LocalDate settlementDate String correctionFor String eksterntOppgjNr Map context } class PersistedTransaction { +String transactionType +String JSON } class ParsedAnnex { Boolean ?cancel BigDecimal priceContribution BigDecimal ?foreignAmount String ?guid String annexRef Map ?attributes String ?description Map ?context BigDecimal ?price } PersistedSettlement "1" --* "0..1" PersistedTransaction : persisted transactions PersistedTransaction "1" --* "1..n" ParsedAnnex : parsed annexes ParsedAnnex "1" --* "0..n" ParsedAnnex : parameters ParsedAnnex "1" --* "0..n" ParsedAnnex : subannexes (recursive) class PersistedSettlement:::transStyle class PersistedTransaction:::persistedStyle class ParsedAnnex:::annexStyle ``` ### Persistent Storage and Transaction Boundaries `PersistedSettlement` and `PersistedTransaction` represent settlements and transactions as stored in the Clearing system. These define the atomic units of work for settlement processing and establish important operational boundaries for API integration. Transaction content is stored as JSON, enabling the flexible structure that makes Generic Settlements possible. The key distinction between persistent and parsed structures lies in their identity management: **Settlement processing guarantees:** - Settlements are processed atomically — they either succeed completely or fail entirely (COMMIT or ROLLBACK semantics) - Individual `PersistedTransaction` entries can be replaced through correction settlements to resolve processing failures - Corrections cannot target individual annexes or parameters within the JSON structure, only complete transactions can be replaced - Annexes may include custom GUIDs in the incoming settlement for external tracking purposes - The Clearing system assigns transient GUIDs to all annexes without client provided GUID, useful for aggregation and reporting **Key point:** Settlement and transaction identities are persistent and stable across systems (GUI, API, logs). Annex identities within the JSON structure are transient unless explicitly provided as GUIDs by the client. ### Structure Inheritance The Generic Settlement structure uses inheritance to propagate attributes and context values through the hierarchy. The following overview is essential to understand the importance of constructing settlements correctly. **Inheritance rules:** - **Annex identity inheritance:** All annex IDs are inherited from parent annexes and automatically added to child annex attributes - **Parameter propagation:** Parameters add their ID, attributes, and context values to their associated annex - **Recursive attribute inheritance:** All annex attributes and context values cascade recursively from parent to child annexes **Benefits:** This inheritance model enables concise settlement representation by sharing common data across hierarchies, reducing redundancy and simplifying structure while maintaining full context at every level. From the example above, the effective attributes and context for annex `Product:345` are: - **Attributes:** - ids: - POS:OsloS - DCI:App - id=Product:345 - id=SalesPackage:123 - id=Discount:Child - keyB=valueB - keyC=valueC - keyD=valueD - **Context:** - keyF=valueF - keyG=valueG Note that keyE=valueE is not included, as it belongs to sibling annex `Product:456` and does not propagate to `Product:345`. The inheritance of attributes in particular enables clearing rules to target specific combinations of annexes and parameters, such as applying custom logic when `Product:345` appears under discount `Discount:Child` within the context of `SalesPackage:123`. :::note The entire settlement is during the normalization phase of the clearing process modelled as a single hierarchical tree structure. The settlement itself appears to the clearing engine as the root of a single annex. This inheritance model is the core mechanism that enables the Clearing system to flatten hierarchical tree structures into tabular rows for clearing and reporting, where each row contains the complete inherited context from its ancestor chain. Each possible path from the root annex to a leaf annex represents a potential row in the flattened dataset. ::: ## Example: Birthday Package Settlement The following example demonstrates a Generic Settlement for a complex multi-party transaction; a birthday package sale at ACME Cafe. This example deliberately uses a non-transport scenario to illustrate the structure's flexibility beyond fare products. **Business scenario:** ACME Cafe sells a birthday package combining products from partners Baker Hansen (BKH) and The Coffee Experts (CFE) with entertainment services provided by external clown providers. The sale includes: - A seasonal Christmas campaign discount on all packages - Senior citizen rebates - Room rental fees for hosting the party - A composite product sourced partly from external partners (BKH and CFE) ```mermaid graph TD S["Settlement
posRef: ACM:Pos:1
settlementNumber: 31
settlementDate: 2025-08-02"] T1["Transaction
ACMSALESPACKAGE
(sumTotal: 600.00)"] T2["Transaction
ACMPAY
(sumTotal: 600.00)"] A1["Annex
ACM:SalesPackage:Birthday
priceContrib: -0.01"] A2["Annex
ACM:Payment:Payment
priceContrib: 600.00
paymentType: CASH"] P1["Parameter
ACM:Campaign:Christmas2025
priceContrib: -100.00"] P2["Parameter
ACM:Fee:RoomRental
priceContrib: 200.00"] SA1["Sub-Annex
ACM:Product:CoffeeAndCake
priceContrib: 0.00"] SA2["Sub-Annex
ACM:Service:Clown
priceContrib: 500.01
clownProvider: ACM:HireService:ClownServicesLtd"] P3["Parameter
ACM:Discount:Senior
priceContrib: -10.00"] SSA1["Sub-Annex
CFE:Product:Coffee
priceContrib: 20.00"] SSA2["Sub-Annex
BKH:Product:Cake
priceContrib: 65.00"] SSA3["Sub-Annex
ACM:Product:Milk
priceContrib: 5.00"] SSA4["Sub-Annex
BKH:Takeaway:Goodiebag
priceContrib: 10.00"] S --> T1 S --> T2 T1 --> A1 T2 --> A2 A1 --> P1 A1 --> P2 A1 --> SA1 A1 --> SA2 SA1 --> P3 SA1 --> SSA1 SA1 --> SSA2 SA1 --> SSA3 T1 --> SSA4 classDef settlStyle fill:#e1f5ff,stroke:#333,stroke-width:2px, color:#000 classDef transStyle fill:#ffffff,stroke:#333,stroke-width:2px, color:#000 classDef annexStyle fill:#fff2cc,stroke:#333,stroke-width:2px, color:#000 classDef paramStyle fill:#d9ead3,stroke:#333,stroke-width:2px, color:#000 class S settlStyle class T1,T2 transStyle class A1,A2,SA1,SA2,SSA1,SSA2,SSA3,SSA4 annexStyle class P1,P2,P3 paramStyle ``` The example above can be cleared by submitting the following JSON representation. ```json { "posRef": "ACM:Pos:1", "distributionChannelRef": "ACM:DistributionChannel:Cafe", "settlementNo": 36, "settlementDate": "2025-08-02", "comments": [{"comment":"One of the 100-bills looks a bit off."}], "context": { "externalBatchId": "12345" }, "genericTransactions": [ { "transactionType": "ACMSALESPACKAGE", "genericAnnexes": [ { "annexRef": "ACM:SalesPackage:Birthday", "description": "Birthday package", "priceContribution": { "amount": "-0.01" }, "parameters": [ { "annexRef": "ACM:Campaign:Christmas2025", "priceContribution": { "amount": "-100.00", "taxRate": "25.00", "taxCode": "25" } }, { "annexRef": "ACM:Fee:RoomRental", "priceContribution": { "amount": "200.00", "taxRate": "12.00", "taxCode": "12" }, "context": { "roomNumber": "42", "numberOfHours": 4 } } ], "subAnnexes": [ { "annexRef": "ACM:Product:CoffeeAndCake", "priceContribution": { "amount": "0.00", "taxRate": "15.00", "taxCode": "15", "currency": "NOK" }, "parameters": [ { "annexRef": "ACM:Discount:Senior", "priceContribution": { "amount": "-10.00", "taxRate": "25.00", "taxCode": "25", "currency": "NOK" }, "context": { } } ], "subAnnexes": [ { "annexRef": "CFE:Product:Coffee", "priceContribution": { "amount": "20.00", "taxRate": "25.00", "taxCode": "25", "currency": "NOK" } }, { "annexRef": "BKH:Product:Cake", "priceContribution": { "amount": "65.00", "taxRate": "25.00", "taxCode": "25", "currency": "NOK" } }, { "annexRef": "ACM:Product:Milk", "priceContribution": { "amount": "5.00", "taxRate": "25.00", "taxCode": "25", "currency": "NOK" } } ] }, { "annexRef": "ACM:Service:Clown", "attributes": { "clownProvider": "ACM:HireService:ClownServicesLtd" }, "priceContribution": { "amount": "500.01", "taxRate": "12.00", "taxCode": "12", "currency": "NOK" }, "context": { "clownName": "Bubbles" } } ] }, { "annexRef": "BKH:Takeaway:Goodiebag", "priceContribution": { "amount": "10.00", "taxRate": "15.00", "taxCode": "15", "currency": "NOK" } } ] }, { "transactionType": "ACMPAY", "genericAnnexes": [ { "annexRef": "ACM:Payment:Payment", "priceContribution": { "amount": "600.00", "taxRate": "0.00", "taxCode": "00", "currency": "NOK" }, "attributes": { "paymentType": "CASH" } } ] } ] } ``` ### Understanding the Settlement Structure **Transaction composition:** - Settlements contain one or more transaction types, each representing a distinct business operation - This example includes `ACMSALESPACKAGE` (representing the sale) and `ACMPAY` (representing payment collection) - Each transaction type may have specific clearing and reporting requirements **Hierarchical relationships:** - Parameters apply to their parent annex and cascade to all nested sub-annexes - This hierarchical structure enables proportional distribution of adjustments (discounts, fees) across multiple components - Annexes can be nested to model complex product structures **Identifiers and price contributions:** - Each annex and parameter requires a unique `annexRef` identifier following the namespace format (`NAMESPACE:TYPE:IDENTIFIER`) - Price contributions can be positive (revenue, fees) or negative (discounts, refunds) - Transaction totals equal the sum of all annex and parameter price contributions **Tax handling:** - Different annexes may have distinct tax rates and codes based on product/service classification - Tax information (`taxRate`, `taxCode`) is specified per price contribution - In this example, tax rates range from 0% (not applicable for payments) to 25% (standard VAT) - Discounts and fees may span multiple tax rates, making the clearing more complex **Price adjustments:** - The top-level annex includes a `-0.01` price contribution to round the total to a whole number - This adjustment technique ensures customer-facing prices match business requirements **Extensibility:** - Use `attributes` to provide data that influences clearing logic (e.g., `paymentType`, `clownProvider`) - Use `context` to include supplementary reporting data (e.g., `roomNumber`, `clownName`) - Context values must be explicitly referenced in reporting templates to appear in reports ### Clearing Flexibility and Business Logic The settlement structure provides _information_ for clearing but does not dictate clearing behavior. Actual clearing logic is determined by Clearing Mappings configured in the Clearing system. This is done by Entur. **Example clearing scenarios:** - **Context-driven reporting:** The room rental fee parameter includes `roomNumber` and `numberOfHours` context values that enable detailed facility utilization reports - **Provider-specific routing:** The clown service annex uses the `clownProvider` attribute to support separate clearing agreements with different service providers - **Partner revenue sharing:** External partner products (BKH, CFE) are modeled as sub-annexes, enabling accurate revenue distribution and inter-company accounting between ACME Cafe and its suppliers - **Commission extraction:** Clearing rules can calculate and allocate commissions on partner product sales, ensuring ACME receives their contractual revenue share - **Proportional adjustments:** The senior discount parameter applies to the `CoffeeAndCake` annex and cascades to all sub-annexes, automatically distributing the discount across multiple partners and tax codes weighted by their respective `priceContribution` values ## Settlement Corrections Any modification to previously submitted transactions requires a correction settlement. Due to the batched processing architecture, settlements may have already been cleared and reported before corrections are identified, making direct modification of previously submitted settlements impossible. **Correction mechanism:** Corrections use a two-step approach within a single settlement: 1. **Reversal:** A complete reversal of the original transaction (DEBIT and CREDIT switched), negating the original entry in the General Ledger 2. **Replacement:** A new transaction containing the corrected data, effectively superseding the original **Refunds as corrections:** Refunds follow the same pattern but serve a different business purpose: 1. **Reversal:** A complete reversal of the original sales transaction (DEBIT and CREDIT switched), negating the original entry 2. **Credit:** A new credit transaction that returns funds to the customer **Implementation:** - Set the `cancel` field to `true` on the root annex in the reversal transaction - Include both the cancellation and replacement transactions in the same settlement submission - Optionally reference the original settlement using the `correctionFor` field at the settlement level **Key point:** Corrections must include both the reversal and optional replacement within a single settlement to maintain proper accounting and audit trails. ## Client Responsibilities Clients submitting settlements act as **Settlement Agents** in Entur clearing terminology. A Settlement Agent is the authenticated organization responsible for submitting settlements on behalf of one or more clearing partners. **Settlement Agent scope:** Typically, a Settlement Agent represents only itself. However, in marketplace or platform scenarios, a single Settlement Agent may represent multiple partners. For example, Entur acts as the Settlement Agent for all partner products sold through its platform. **Delegated responsibilities:** The Settlement Agent is a trusted role with delegated responsibility for ensuring settlement accuracy and completeness. This includes: - **Structural correctness:** Verify that settlements are properly formatted and balanced - **Authorization:** Ensure proper authentication and authorization for all submitted data - **Data scope:** Include only information relevant to the Agent and its partners - **Validation:** Confirm that point of sale references, distribution channels, VAT codes, and tax rates are correct - **Legal compliance:** Recognize that submitted settlements constitute legal vouchers for accounting purposes **Validation and correction:** Depending on incoming data quality, Settlement Agents may need to implement local staging areas for validation and correction before submission to the Clearing system. :::info The Clearing system performs validation during settlement processing, but the failed settlement lists is not currently self-serviced. Any settlement failing clearing requires manual analysis and correction by the Chart of Accounts Administrator in cooperation with the Settlement Agent. ::: :::warning Under Norwegian accounting regulations, submitted settlements are considered vouchers for accounting data. The Settlement Agent assumes full responsibility for data accuracy, completeness, and compliance with accounting and VAT reporting requirements. ::: ## Best Practices Multiple approaches exist for modeling settlements. Consider these best practices when creating Generic Settlements: ### Settlements Must Be Balanced A settlement must ultimately balance (SUM DEBIT = SUM CREDIT). For example, the Payment transaction must accompany the Sales Package transaction within the same settlement. The specific balancing mechanism depends on your business scenario, the clearing configuration and accounting rules configured. **Key point:** Submitting separate settlements for each transaction type will likely fail, as each settlement must be balanced independently. ### Transaction Types Should Represent Logical Units of Work Transaction types define logical units of work with shared context. For example, a sales package transaction (`ACMSALESPACKAGE`) and its associated payment transaction (`ACMPAY`) are separate transaction types with distinct clearing and reporting requirements. Each transaction type typically has several associated reporting templates showing columns relevant to that transaction's context. :::info New transaction types must be registered by the Clearing administrator and assigned to all relevant Charts of Accounts before they can be submitted in settlements. ::: **Key point:** New transaction types require careful analysis and registration before use. ### Hierarchical vs. Flat Annex Structures Each price contribution can be represented as a separate annex directly under the transaction. However, this flat structure eliminates the ability to leverage annex relationships when defining clearing rules. For example, clearing rules can target specific parent-child annex combinations, such as applying custom accounting logic when `ACM:HireService:ClownServicesLtd` appears under `ACM:Campaign:Christmas2025`. The hierarchical structure also enables proportional distribution of rebates and discounts across multiple annexes based on their relative price contributions. **Key point:** Design the annex structure to match your clearing logic requirements. Use hierarchical nesting when clearing rules need to consider annex relationships. ### Deep Annex Structures vs. Multiple Transactions In our example, the takeaway goodie bag (`BKH:Takeaway:Goodiebag`) is modeled as a separate annex under the birthday sales package transaction (`ACM:SalesPackage:Birthday`). However, this structure may be problematic if the cafe needs to refund the goodie bag independently of the rest of the birthday package. **Key point:** Split annexes into separate transactions when they require independent correction or refund capabilities. ### Annex vs Parameter Parameters are functionally similar to simply adding a parent annex with equivalent values, but parameters exhibit distinct inheritance behavior: **Bidirectional inheritance:** - The parameter inherits attributes and context from its associated annex (child-like behavior) - The associated annex inherits values from the parameter (parent-like behavior) **Clearing perspective:** - Parameters can be cleared as child annexes of their associated annex - Associated annexes can simultaneously be cleared as child annexes of their parameters This bidirectional relationship creates a unique inheritance pattern. While the recursive structure technically allows parameters to have sub-annexes, this practice should be avoided. **Key point:** Use parameters as modifiers (such as discounts, fees, or adjustments) applied to robust annex structures rather than creating structural variations for each modification. This enables clearer semantics and better reuse of existing clearing logic. ### Attributes vs. Context Use **attributes** for data that drives clearing logic, such as payment types or service provider identifiers. Use **context** for supplementary information needed for reporting or analysis that doesn't affect clearing rules. **Important considerations about the Clearing system:** - It's _not_ a general-purpose data store. Include only essential reporting data in context: external references or critical metadata, not large data payloads. - It may produce datasets containing the context values, but context _not relevant for clearing_ should be joined with these datasets locally using external references from the datasets, not embedded directly in the settlement. - Context values are not automatically included in reports. Each context key must be explicitly referenced in a reporting template column. - Several context keys are already standardized and must be used as specified to ensure compatibility with existing reports. Consult the support team for details on standardized context keys. **Key point:** Use attributes for clearing logic and context for reporting. Collaborate with the Chart of Accounts administrator when designing context for new transaction types to maintain compatibility with existing reporting templates. ### Generic Settlements and High Transaction Volumes The Clearing system can process large volumes of transactions efficiently. However, the Generic Settlement API is optimized for moderate-sized settlements rather than bulk processing. Submitting settlements containing thousands of transactions and multi-megabyte JSON payloads introduces reliability and performance risks. Instead, distribute high-volume transaction data across multiple smaller settlements submitted at regular intervals. For scenarios requiring continuous high-volume processing, a streaming-based integration module may be more appropriate. This capability will be developed based on identified use cases. **Key point:** Split high-volume transaction data into multiple smaller settlements. ### Resubmitting Settlements The Clearing system supports settlement resubmission using the same `posRef` and `settlementNumber` combination. If a settlement with matching identifiers has already been successfully received, the resubmission will be rejected to prevent duplicate processing. **Client responsibilities:** - Generate sequential settlement numbers for each settlement submission - Implement retry logic to resubmit failed settlements (within reasonable limits) Note that the duplicate detection mechanism is limited to settlements submitted within the last 7 days, it is only intended to handle transient submission failures. Older duplicates will be detected and failed during clearing. **Key point:** Settlement identifiers (`posRef` + `settlementNumber`) must be unique and sequential. Resubmit failed settlements using the same identifiers; do not create new settlement numbers for retry attempts. ### Identifier Requirements and Namespacing The Clearing system is designed to process settlements from partners who may not use the broader Entur platform. This necessitates a highly flexible approach to identifier management. **Namespaced References ("refs"):** All identifier fields suffixed with `Ref` (such as `posRef`, `distributionChannelRef`, `annexRef`, etc.) must be globally unique. This is achieved by enforcing a namespaced format: `NAMESPACE:TYPE:IDENTIFIER`. For example: `ACM:SalesPackage:Birthday`. Each namespace must be registered with Entur prior to use. :::info The Clearing system maintains an internal mapping of refs to human-readable names, so descriptive labels are not required in the settlement payload. ::: **Attribute Identifiers:** Identifiers used within the `attributes` map (e.g., `paymentType`, `clownProvider`) are not required to be globally unique or follow a specific format. These are key-value pairs that may be referenced in clearing logic. Keys and values should be concise, meaningful strings without special characters. The value may also be a namespaced ref. **Context Identifiers:** Identifiers within the `context` map (e.g., `externalBatchId`, `roomNumber`) are also not required to be globally unique or follow a specific format. These values typically provide supplementary metadata for reporting or audit purposes. :::warning When attribute or context values represent entities shared across partners (such as `clownProvider` in revenue-sharing scenarios), naming conventions must be coordinated to ensure consistent interpretation in clearing logic. ::: **Summary:** - All refs must be globally unique and namespaced. - Attribute and context identifiers are flexible but should remain meaningful and consistent. - Any ref can be assigned a display name for use in the GUI and reports. ### Validation and Schema Flexibility The Generic Settlement structure provides flexibility but does not accept arbitrary data structures. While basic structural validation occurs during submission, most validation is deferred to the asynchronous clearing process. The Clearing system performs comprehensive consistency checks during clearing ("mottakskontroll"). Any validation failures cause the entire settlement to be rejected, requiring manual intervention. **Validation considerations:** - Schema validation is intentionally minimal. The effective "schema" is defined implicitly by clearing mappings and reporting templates configured in the Clearing system. - As common patterns emerge, the system may introduce stricter validation for specific context values to ensure consistent reporting, especially for transaction types shared across multiple Charts of Accounts. - Any changes to validation that is not compatible with existing settlements will be carefully analysed and communicated in advance. - Incorrect structures may pass initial validation but fail during clearing or produce invalid reports. **Key point:** Thoroughly validate settlement structures before submitting large volumes. Test with small batches first to avoid creating backlogs of failed settlements that require manual correction by the Chart of Accounts administrator. **Key point:** Settlements may be unbalanced or structurally incorrect for any number of reasons (client bugs, delays, infrastructure issues etc). The Client must implement local validation and correction facilities before submission. --- ## Document: Vehicle Positions A GraphQL API for real-time vehicle positions, delays, and occupancy for public transport in Norway. URL: /docs/open-services/vehicle-positions # Vehicle Positions The Vehicle Positions API is a GraphQL service that provides real-time positions and status for public transport vehicles across Norway. It enables fetching and streaming live vehicle data including location, delays, occupancy, and journey information. [API Reference](/open/api/graphql/vehicle-positions) ## WebSocket Subscriptions For real-time streaming updates, the API provides GraphQL subscriptions over WebSocket: **WebSocket URL:** wss://api.entur.io/realtime/v2/vehicles/subscriptions Subscriptions allow your application to receive continuous updates as vehicle positions change, rather than polling for data. ### Example Subscription Connect to `wss://api.entur.io/realtime/v2/vehicles/subscriptions` with the `ET-Client-Name` header. Subscribe to vehicle updates within a geographic bounding box: ```graphql subscription { vehicles( boundingBox: { minLat: 59.9 maxLat: 60.0 minLon: 10.7 maxLon: 10.8 } ) { vehicleId location { latitude longitude } bearing delay line { publicCode } } } ``` ## Additional Resources - [Real-Time Data Overview](/open-data/realtime) - Information about SIRI and GTFS-RT feeds --- ## Document: Mobility The Mobility API provides real-time shared mobility data from bike and scooter operators across Norway. URL: /docs/open-services/mobility # Mobility The Mobility API is an aggregation service for shared mobility data in Norway. It provides access to real-time information about shared bikes, e-scooters, and other mobility services from multiple operators across Norwegian cities. [API Reference](/open/api/graphql/mobility) The API offers two interfaces: - **GraphQL API** - A client-centric API for aggregating data across all providers - **GBFS Feeds** - Standardized feeds following the General Bikeshare Feed Specification ## GBFS Feeds The Mobility API exposes standardized GBFS feeds for all aggregated operators. Data is served in GBFS version 2.3 and version 3.0 formats. **GBFS v2.3 Base URL:** https://api.entur.io/mobility/v2/gbfs **GBFS v3.0 Base URL:** https://api.entur.io/mobility/v2/gbfs/v3 ### Available GBFS Endpoints For GBFS v3.0, a manifest listing all available systems can be found at: - `GET https://api.entur.io/mobility/v2/gbfs/v3/manifest.json` To get feeds for a specific operator in GBFS v3.0: - `GET https://api.entur.io/mobility/v2/gbfs/v3/{system}/gbfs` Where `{system}` is the system identifier (e.g., "oslobysykkel", "voistavanger"). ### Standard GBFS Feed Types Each system typically provides the following feeds: - `gbfs.json` - Auto-discovery file for all feeds - `system_information.json` - System metadata - `station_information.json` - Station locations and capacity (for station-based systems) - `station_status.json` - Real-time station availability - `free_bike_status.json` - Real-time vehicle locations (for free-floating systems) - `vehicle_types.json` - Vehicle type definitions - `system_pricing_plans.json` - Pricing information --- ## Document: Zones in NeTEX Definitions of Zonal concepts in NeTEX URL: /concepts/NeTEX/zonal # Zones in NeTEX ## TariffZone A ZONE used to define a zonal fare structure in a zone-counting or zone-matrix system. Example found [in GitHub repository](https://github.com/entur/profile-norway-examples/blob/master/netex/submodels/site/submodel-StationWithEquipment.xml). Description on Confluence: https://entur.atlassian.net/wiki/spaces/PUBLIC/pages/728727661/stops#TariffZone :::warning The `TariffZone` concept is generally deprecated in favor of `FareZone` throughout Entur's APIs. ::: ## FareZone A specialization of TARIFF ZONE to include fare related zonal information. Example found [in GitHub repository](https://github.com/entur/profile-norway-examples/blob/master/netex/submodels/site/submodel-StationWithEquipment.xml). Description on Confluence: https://entur.atlassian.net/wiki/spaces/PUBLIC/pages/728727661/stops#FareZone --- ## Document: Stops in NeTEX Definitions of stop point concepts in NeTEX URL: /concepts/NeTEX/stops # Stops in NeTEX For diagrams and more detailed description of the NeTEX data model for stops, see this [Confluence page](https://entur.atlassian.net/wiki/spaces/PUBLIC/pages/728596522/Data+models#Stops). ## Group Of Stop Places A grouping of STOP PLACEs which will be commonly referenced for a specific purpose. The term corresponds to a specialisation of standard Transmodel concept GROUP OF ENTITIES. ## Stop Points A stop point ([StopPlace](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370393/Generell+informasjon+NeTEx#GenerellinformasjonNeTEx-StopPlace)) is a special type of site ([Site](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370393/Generell+informasjon+NeTEx#GenerellinformasjonNeTEx-Site)) normally located in a :def[Tariff Zone]. As a Site, a StopPlace can have multiple- Parkings, Levels (each one with its own Entrance), and accessibility Equipment. In addition, a StopPlace is divided into subordinate Quays (and below the Quay, Boarding Positions). Each StopPlace can also have waiting areas (Access Space) and footpaths (NavigationPath). The structure of stop places is subject to variation. It can be anything from a simple kerb stop, to the most complex transport hubs. The following structure should be used to describe a stop place: - A StopPlace always has at least one Quay. - A StopPlace may have AccessSpaces. - A StopPlace may have a parent StopPlace (maximum 1 level of nesting). - Two or more StopPlaces, including parent StopPlaces, can be grouped into a GroupOfStopPlaces. - A Quay can have BoardingPositions (usually only relevant to trains). ### Stop Place A place comprising one or more locations where vehicles may stop and where passengers may board or leave vehicles or prepare their trip. A STOP PLACE will usually have one or more well-known names. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/PUBLIC/pages/728727661/stops#StopPlace). ### Stop Place Space A physical area within a STOP PLACE, for example, a QUAY, BOARDING POSITION, ACCESS SPACE or EQUIPMENT PLACE. Read more on [Confluence](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/728727661/stops#StopPlaceSpace). ### Quay A place such as a platform, stance, or quayside where passengers have access to PT vehicles, Taxi, cars or other means of transportation. A QUAY may serve one or more VEHICLE STOPPING PLACEs and be associated with one or more STOP POINTS. A QUAY may contain other sub QUAYs. A child QUAY must be physically contained within its parent QUAY. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/PUBLIC/pages/728727661/stops#Quay). #### Boarding Position A location within a QUAY from which passengers may directly board, or onto which passengers may directly alight from, a VEHICLE. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/ROR/pages/637370400/stops#BoardingPosition). ### Access Space An area within a STOP PLACE that does not give direct access to transport vehicles. May be connected to QUAYS by PATH LINKs. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/ROR/pages/637370400/stops#AccessSpace). ## Paths ### Path Link A link between any two PLACEs (That is STOP PLACEs, ACCESS SPACEs or QUAYs, BOARDING POSITIONs, POINTs OF INTEREST etc or PATH JUNCTIONs) that represents a step in a possible route for pedestrians, cyclists or other out of vehicle passengers within or between a PLACE. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/ROR/pages/637370400/stops#PathLink). ### Path Junction A designated point, inside or outside of a STOP PLACE or POINT OF INTEREST, at which two or more PATH LINKs may connect or branch. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/ROR/pages/637370400/stops#PathJunction). ### Navigation Path A designated path between two places. May include an ordered sequence of PATH LINKs. Read more on [Confluence](https://entur.atlassian.net/wiki/spaces/ROR/pages/637370400/stops#NavigationPath). --- ## Document: Personnel tickets Provide reduced fares on train travel for employees and pensioners within participating companies in the Norwegian railway industry, as well as eligible family members. URL: /docs/partner-services/sales-platform/personnel-tickets # Personnel tickets :::lead Provide reduced fares on train travel for employees and pensioners within participating companies in the Norwegian railway industry. Family members such as spouses, partners, and dependent children may also be eligible for discounted travel under the personnel ticket scheme, subject to defined eligibility criteria. ::: ### Ownership and responsibilities The scheme is owned by the Norwegian Railway Directorate and technically operated and managed by Entur. Entur provides the infrastructure that enables companies to register eligible users, maintain their entitlements, and ensure that discounts are correctly applied when tickets are purchased. ### Prerequisites Companies that wish to offer personnel tickets to their employees must enter into a personnel ticket agreement with Entur. This agreement defines the rules for eligibility, usage, and reporting within the scheme. Once the agreement is in place, the company can obtain authentication credentials and begin integrating with the available APIs. ### What you can do with the APIs Once onboarded, partner companies can use Entur's APIs to - Register and manage employees and eligible family members - Connect customer profiles to their personnel ticket rights - Enable discounted ticket purchases for personnel ticket holders - Retrieve reports on personnel ticket usage In practice, this means that employees registered in the scheme can access discounted fares when purchasing tickets from participating railway operators, based on the rights assigned by the personnel ticket system. The assignment of personnel ticket rights is based on the rights assigned to them by the personnel ticket system, using employee data provided by their employer. --- ## Document: Personalisation Tailored ticket concepts for cases where the standard pricing structure does not achieve the desired effect. URL: /docs/partner-services/sales-platform/personalisation # Personalisation :::lead Create tailored ticket concepts for cases where the standard pricing structure does not achieve the desired effect. This is done through two main types: campaign codes that provide a direct discount at the point of purchase, and loyalty programs that reward travelers based on travel history. ::: The rewards given through the personalisation service are available through [the offers API](/docs/partner-services/sales-platform/offers). Personalisation programs can be split into two different categories: - campaign code programs where rewards are given to anyone with the access to a campaign code - loyalty programs, where rewards are given depending on the customer’s own travel pattern. ### Campaign code programs You can configure your own campaign code program using Entur Partner. If you do not have access, contact Entur support. ### Loyalty programs Loyalty programs can be configured to suit your organisation’s needs, here’s some examples of features: - Automatic membership for a customer when purchasing relevant products or adding them manually when customer opts in. - Use events generated on purchasing of products through Entur’s sales platform to e.g. give member points - The possibility to connect events from your organisation’s system using HTTP-requests or Kafka - Different rewards depending on amount of points the member has accumulated within a period. E.g. 5% discount on a ticket after 5 purchased tickets within a month. - Capping towards a limit within a defined time period, e.g. the price of a monthly ticket within a month. - Pausing accumulation of points or giving rewards for time periods to prevent “gaming”. If you are unsure if this service will suit your organisation’s needs or you want to create a personalisation program, feel free to contact us at team.personalisering@entur.org --- ## Document: Customers Create and manage customer profiles in the sales platform. URL: /docs/partner-services/sales-platform/customers # Customers :::lead Store customer profile information for use in the sales platform. ::: Some of Entur's services require that the customer is registered in Entur's customer database and has a :def[customer-number|customer number]. The profiles API is used to create and manage customers in the Entur system. It offers a variety of different fields that can be set, but most are optional. Customer profiles are not shared between organisations. Organisations can also give profiles their own :def[customer-reference|customer reference]. ## Permanent profiles A permanent profile is a profile for a customer that is registered and using the same profile for buying tickets. [See the profiles client in the profiles API](/apis/customers/profiles-client) ## Temporary profiles Temporary profiles can be used to allow anonymous purchasing of tickets. These profiles require an expiration date, usually set to a time after the journey is completed. A temporary profile cannot be reused, but it can be converted to a permanent profile in case the customer decides to register after the purchase. If the customer already has a permanent profile, the temporary profile can be merged with the permanent profile using the [connect profile to permanent profile endpoint](apis/customers/profiles-client#connect-a-profile-to-a-permanent-profile). [See the temporary profiles client in the profiles API](/apis/customers/temporary-profiles-client) ## Preferences The preferences API allows you to define preferences for your organisation and add these preferences to the customer's profile. Examples of preferences can be preferred user type when purchasing tickets, whether they are using a wheelchair or other types of assistance, et cetera. It is up to your organisation how you use this data. [See the preferences client in the profiles API](/apis/customers/preferences-admin) ## Customer accounts The connection between a customer profile and the customer account when using the [Account Based Ticketing Solution](/docs/partner-services/ticketing/account-based-ticketing) is maintained in the profiles client. A customer can have multiple customer accounts. [See the customer accounts client in the profiles API](/apis/customers/customer-accounts-client) ## Deleting profiles To delete a profile you have to deactivate the customer. An expiration date is required in the request, which is the date when the profile is deleted from the database. The profile cannot be used after the deactivation is done, but it is recoverable until deletion. We recommend that this date is set to 2-3 days in the future, in case the customer deletes its profile by accident. When a customer is deactivated, a Kafka event is produced. This event triggers deletion of data connected to the profile in Entur's system. See the [deactivate customer documentation](/apis/customers/profiles-client#deactivate-customer) and [restore deactivated customers documentation](/apis/customers/profiles-client#restore-deactivated-customer) ## Kafka events Whenever a change is made to customer profiles for your organisation. This includes creations, updates, and deletions of profiles. Contact us at team.personalisering@entur.org to subscribe to these topics. Topic names for production: - customer-changed-production-\[organisation ID] --- ## Document: Consents A system for storing and managing consent terms for your organisation and consents given by your customers to these terms. URL: /docs/partner-services/sales-platform/consents # Consents :::lead Store and manage consent terms for your organisation and consents given by your customers to these terms. It is a flexible API/system/service, where you can add as many terms as you like in any language. It also enables terms to be shared across organisations for a quick and easy setup. ::: ## Using the consent system as a Partner Please see the guide [Administrating consents](/docs/guides/consents) on how to get started with creating consent terms and collecting given consents for you organisation. ## Consents across organisations The same consent terms can be used across organisations. Using templating for the organisation name, generic consent terms can be created and used by multiple organisations. The customers will still have to give their consent per organisation, even if the terms are the same. Only Entur have access to create shared consents, contact us at team.personalisering@entur.org if you want to use this. ## Staying updated with your organisation’s consent terms and consents given The consent service produces events on Kafka whenever consent terms have been created or changed, and for all changes in given consents. Contact us at team.personalisering@entur.org to subscribe to topics for your organisation. ### The topics available are: - consent-base-changed-production-\[organisation ID] - All changes to consent bases for your organisation, including creation and deletion. - consent-changed-production-\[organisation ID] - All changes to consents for your organisations, including creation and deletion. - given-consent-changed-production-\[organisation ID] - All changes to given consents for your organisations, including creation and deletion. ## Export all given consents You can use the [datawarehouse API](/apis/consents/consents-dwh) to export full list of given consents by your customers ## Note on customer deletion When a customer is deleted in the Entur database, the consents given by the customer will also be deleted automatically. So there is no need to delete given consents in a separate operation. --- ## Document: Rate Limiting Rate limiting policies for Journey Planner API requests, including quotas and spike arrest limits. URL: /docs/open-services/journey-planner/rate-limiting # Rate Limiting To ensure stability and fair usage across all consumers, rate-limiting policies apply to all Journey Planner API requests. Users without an agreement with Entur are subject to the default policy, while Entur partners receive a custom policy. ## Policies There are two separate policies: - **Trip-request** — One policy only applies for trip-requests as these are the most resource consuming. - **Other-request** — One policy applies for all other requests available in the GraphQL API. Each policy is split into two elements: - **Quota** — The number of requests per minute, calculated using a counter within a time window of one minute that starts at the first request and is reset every minute. E.g. given a quota policy of 10 requests per minute, a violation will occur if a request is sent after the counter has reached its limit of 10 requests within the current time window. - **Spike Arrest** — The number of requests per second, calculated by keeping track of time elapsed since last request. E.g. a spike arrest policy of two requests per second means a violation will occur if a request is sent within half a second after the previous request. ## Policy levels | Level | Trip-request Quota | Trip-request Spike Arrest | Other-request Quota | Other-request Spike Arrest | |---|:---:|:---:|:---:|:---:| | Non-identified consumers | 30 | 2 | 60 | 20 | | Consumers identified with `ET-Client-Name` | 500 | 150 | 1000 | 200 | | Entur Partners | custom | custom | custom | custom | All requests **must** include the `ET-Client-Name` header. Use a value that uniquely identifies your company and application, in the form `-` (lowercase, no spaces). For details, see [Authentication](/docs/authentication#open-services). ## Monitoring policy status It is expected that consumers have control over their policy status with respect to traffic patterns. All responses from the service contain headers with details about current usage and remaining quota. When spike arrest occurs, headers are supplied containing the spike arrest policy itself. If your request violates one of the policies you will get a response with status code `429` ([Too Many Requests](https://datatracker.ietf.org/doc/html/rfc6585#section-4)). ### Quota headers All responses include quota headers (except when there is a spike arrest violation): ``` Rate-Limit-Allowed: 30 Rate-Limit-Available: 29 Rate-Limit-Expiry-Time: Mon Jan 16 2023 12:17:34 GMT-0000 (UTC) Rate-Limit-Range: "per-minute" Rate-Limit-Used: 1 ``` ### Spike arrest headers Only returned upon a spike arrest violation: ``` Spike-Allowed: 2 Spike-Range: per-second ``` ## Retry policy It makes sense for clients to implement a conservative retry policy on **spike arrest violations** as spikes in traffic loads may occur. Clients should **NOT** implement a retry policy for **quota violations**. Upon quota violation, clients should wait at least until the time indicated by `Rate-Limit-Expiry-Time` before trying again. --- ## Document: Examples Example GraphQL queries for journey planning, departure boards, stop places, and more. URL: /docs/open-services/journey-planner/examples # Examples All example queries below link to the [GraphQL Explorer](https://api.entur.io/graphql-explorer/journey-planner-v3) where you can view, modify, and run them directly. ## Journey planning - [Trip query](https://api.entur.io/graphql-explorer/journey-planner-v3?example=tripQuery) - Basic point-to-point journey planning - [Via trip](https://api.entur.io/graphql-explorer/journey-planner-v3?example=viaTripQuery) - Journey planning with intermediate stops - [Walk only](https://api.entur.io/graphql-explorer/journey-planner-v3?example=walkOnlyQuery) - Walking-only route between two points - [Flexible trip](https://api.entur.io/graphql-explorer/journey-planner-v3?example=flexibleTripQuery) - Journey planning with flexible/on-demand transport - [Entur app query](https://api.entur.io/graphql-explorer/journey-planner-v3?example=enturAppQuery) - Example query similar to the Entur app ## Departure boards - [Departure board](https://api.entur.io/graphql-explorer/journey-planner-v3?example=departureBoardQuery) - Real-time departure board for a stop - [Planned and actual departure times](https://api.entur.io/graphql-explorer/journey-planner-v3?example=plannedAndActualDepartureTimesQuery) - Compare scheduled and real-time departure times ## Stop places - [Stop place](https://api.entur.io/graphql-explorer/journey-planner-v3?example=stopPlaceQuery) - Look up information about a stop place - [Stop place to coordinate](https://api.entur.io/graphql-explorer/journey-planner-v3?example=stopPlaceToCoordinateQuery) - Journey from a stop place to a coordinate ## Filtering - [Authority filter](https://api.entur.io/graphql-explorer/journey-planner-v3?example=authorityFilterQuery) - Filter results by transport authority - [Filter by local bus](https://api.entur.io/graphql-explorer/journey-planner-v3?example=filterByLocalBusQuery) - Filter results to local bus services only - [Situation messages](https://api.entur.io/graphql-explorer/journey-planner-v3?example=situationMessagesQuery) - Retrieve situation/disruption messages ## Mobility - [Bike rental](https://api.entur.io/graphql-explorer/journey-planner-v3?example=bikeRentalQuery) - Query available bike rentals - [Bike rental as access mode](https://api.entur.io/graphql-explorer/journey-planner-v3?example=bikeRentalAccessQuery) - Use bike rental as first/last mile - [Bike rental stations by bounding box](https://api.entur.io/graphql-explorer/journey-planner-v3?example=bikeRentalStationsByBboxQuery) - Find bike rental stations within a geographic area - [Scooter rental](https://api.entur.io/graphql-explorer/journey-planner-v3?example=scooterRentalQuery) - Query available scooter rentals --- ## Document: Debug Tool How to use the OTP Debug Tool for advanced troubleshooting of journey planning queries. URL: /docs/open-services/journey-planner/debug-tool # Debug Tool For advanced debugging and troubleshooting of journey planning queries, Entur provides the **OTP Debug Tool**. **OTP Debug Tool:** [https://otpdebug.entur.org/](https://otpdebug.entur.org/) ## What is the OTP Debug Tool? The OTP Debug Tool is a visual interface for inspecting and debugging the underlying [OpenTripPlanner](https://github.com/entur/opentripplanner) routing engine that powers Journey Planner. It allows you to interact directly with the routing graph and transit data used by the journey planning algorithm. ## What can you do with it? - **Visualize the routing graph** - Inspect the street and transit network that OpenTripPlanner uses for routing - **Explore stop locations** - Browse and search for stop places on the map - **Analyze transit data** - View timetable data, routes, and real-time feeds that are loaded into the search engine - **Debug routing results** - Understand why certain routes are or aren't being suggested for a given query - **Inspect journey details** - Examine the individual legs and transfers of a planned journey ## When to use it The debug tool is particularly useful when: - A journey query returns unexpected results and you want to understand why - You need to verify that specific transit data or real-time updates are correctly loaded - You are investigating routing issues related to specific stops, routes, or geographic areas - You want to understand how the [RAPTOR algorithm](/docs/open-services/journey-planner#the-algorithm-for-finding-the-optimal-path) evaluates different journey options ## GraphQL Explorer For testing and building API queries, use the **GraphQL Explorer** instead: **GraphQL IDE:** [https://api.entur.io/graphql-explorer/journey-planner-v3](https://api.entur.io/graphql-explorer/journey-planner-v3) The GraphQL Explorer lets you write and execute queries against the Journey Planner API, with auto-completion and built-in documentation of the schema. See [Examples](/docs/open-services/journey-planner/examples) for pre-built example queries you can try. --- ## Document: Migrating to Geocoder v3 Migrate from the Geocoder v1/v2 API to v3 URL: /docs/open-services/geocoder/migration-v2-v3 # Migrating to Geocoder v3 Geocoder v3 is a new version of Entur's geocoding API with cleaner parameter names, structured response objects, and unambiguous IDs. This guide maps every v2 parameter and response field to its v3 equivalent. See also the [Geocoder v3 documentation](/docs/open-services/geocoder). ## Parameter changes ### Common (autocomplete + reverse) | v2 | v3 | Notes | |-----------------------------------------------------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `size` | `limit` | | | `lang` | `lang` | unchanged; also accepted on `/place` | | `layers` | `layers` | see [layers](#layers) | | `sources` | `sources` | see [sources](#sources) | | `boundary.country` | `countries` | comma-separated | | `boundary.county_ids` | `counties` | comma-separated | | `boundary.locality_ids` | `localities` | comma-separated | | `tariff_zone_ids` | _(removed)_ | use `fareZones` instead | | _(new in v3)_ | `fareZones` | comma-separated; refs must be FareZone-shaped (`AUTH:FareZone:ID`). | | `tariff_zone_authorities` | _(removed)_ | use `fareZoneAuthorities` instead | | `fare_zone_authorities` | `fareZoneAuthorities` | comma-separated | | `multiModal` | `multimodal` | values: `parent` (default), `child`, `all`; see [multimodal](#multimodal) | | `categories` (v2 reverse only) | `stopPlaceTypes` | NeTEx stop place types; see below | `stopPlaceTypes` takes NeTEx stop place types (`railStation`, `airport`, ...). On its own it restricts results to stop places of those types and excludes other layers - same semantics as v2 `categories`. The v2 layer-like category values (`street`, `vegadresse`, `GroupOfStopPlaces`, `poi`) map to [layers](#layers) instead. Combine `stopPlaceTypes` with an explicit `layers` filter to mix mode-filtered stop places with whole layers in one request. The two compose as a union: the type filter constrains only the `stopPlace` layer, while any other requested layer is returned additively. To get rail stations together with groups of stop places (v2's `categories` OR behaviour, in a single request): ``` ?q=oslo&layers=stopPlace,groupOfStopPlaces&stopPlaceTypes=railStation ``` If `layers` is given but does not include `stopPlace`, the type filter has no stopPlace layer to constrain and is ignored. ### Autocomplete (`/v3/autocomplete`) | v2 | v3 | Notes | |-------------------|-------------|--------------------------------------------------------------------------------------------------------------------| | `text` | `q` | optional in v3: omitting `q` with at least one filter lists all matching places | | `focus.point.lat` | `lat` | focus point latitude | | `focus.point.lon` | `lon` | focus point longitude | | `focus.scale` | `radius` | focus radius in km (default 50, decimals accepted); see [default differs from v2](#default-radius-differs-from-v2) | | `focus.weight` | `weight` | 0-1 (default 0.5); see [weight semantics](#weight-semantics-changed) | | `focus.function` | _(removed)_ | v2's `focus.function` (linear, exp, etc.) is removed; v3 behaves roughly like v2's `exp` | | _(new in v3)_ | `bbox` | restrict results to `minLon,minLat,maxLon,maxLat` - a hard filter, unlike the focus point's soft bias | ### Reverse (`/v3/reverse`) | v2 | v3 | Notes | |--------------------------|----------------|-------------------------------------------------------------------------------------| | `point.lat` | `lat` | query point latitude | | `point.lon` | `lon` | query point longitude | | `boundary.circle.radius` | `radius` | km in both v2 and v3 (decimals accepted) | | _(new in v3)_ | `distanceSort` | sort by distance from the query point (default `true`) or by relevance when `false` | ### Place (`/v3/place`) | v2 | v3 | Notes | |----|----|-------| | `ids` | `ids` | comma-separated; ID shape differs between v2/v3 (see [ID format](#id-format)) | ### `layers` The v3 layer values are the same indexed data v2 already returned, just labelled precisely - in v2 `venue` held NSR stop places and everything else fell under `address`: | v2 `layers` | v3 `layers` | data origin | |-------------|---------------------|------------------------------------------| | `address` | `address` | matrikkel addresses | | `address` | `street` | matrikkel streets | | `venue` | `stopPlace` | NSR stop places | | `address` | `groupOfStopPlaces` | NSR group of stop places | | `address` | `poi` | OSM POIs; `custom-poi` (new in v3) | | `address` | `place` | kartverket-stedsnavn (cities, districts) | **Default behaviour (no `layers` filter):** same result set as v2 - only the `layer` value changed. All layers are eligible, with one exclusion: addresses are hidden from autocomplete unless the query text contains a digit or `sources` includes `kartverket-matrikkelenadresse`. Reverse hides addresses unless the caller opts in via `sources=kartverket-matrikkelenadresse` or `layers=address`. ### `sources` | v2 | v3 | |-------------------|---------------------------------| | `openstreetmap` | `openstreetmap` | | `openaddresses` | `kartverket-matrikkelenadresse` | | _(new in v3)_ | `kartverket-stedsnavn` | | _(new in v3)_ | `nsr` | | _(new in v3)_ | `custom-poi` | ### Weight semantics (changed) `weight` is renamed straight across from `focus.weight`, but the math is different. In v2 it was an open-ended scalar fed through a curve (default ~15). In v3 it is a linear blend between importance ranking (0) and pure location preference (1) - avoid the extremes unless that is what you want: - `weight=0` - no focus bias, results ranked purely on text relevance and importance. - `weight=1` - pure location preference: importance is ignored entirely, only proximity counts. - `weight=0.5` (default) - balanced: importance and proximity contribute roughly equally to ranking. The v3 default tilts toward importance more than v2 does, so far-away major cities can still win against near-focus same-prefix streets (e.g. "Bergen" from Oslo still returns Bergen, not Bergensgata). If you tuned `focus.weight` in v2 do not just copy the number across. ### Default radius differs from v2 Do not copy your v2 `focus.scale` value into v3 `radius`. v2 saturates large values (anything past ~300 km behaves the same, so the v2 default of 2500 was effectively ~120 km); v3 treats the number as a literal focus radius, so `radius=2500` disables the bias entirely. If you used v2's default or any large `focus.scale`, use `radius` in the 50-150 km range. ### Focus parameters are a bundle `lat`, `lon`, `radius`, and `weight` on `/v3/autocomplete` belong together. Sending any of them without both `lat` and `lon` is a 400 error. ### `multimodal` Applies to `/v3/autocomplete` and `/v3/reverse`. An NSR multimodal stop groups several stop places (e.g. a bus terminal + train station hub) under a parent. Most NSR stop places are *monomodal* - standalone, not part of any such group - and those always appear in results regardless of this parameter. `multimodal` only decides whether multimodal parents, children, or both come through alongside them. - `parent` (default) - monomodal stops + multimodal parents; multimodal children hidden. - `child` - monomodal stops + multimodal children; multimodal parents hidden. - `all` - monomodal stops + multimodal parents + multimodal children. The role of each returned stop is reported per feature in the [`stopPlaceRole`](#property-mapping-properties) response field (`parent` / `child` / `standalone`), so you no longer need to infer it from `source` as in v2. ## ID format v3 uses canonical, fully-qualified IDs. v2 uses legacy/abbreviated forms for backwards compatibility. | Entity | v2 ID | v3 ID | |--------------------------------------|-----------------------------------|-------------------------------------------------------------------------------------------| | Stop place | `NSR:StopPlace:N` | `NSR:StopPlace:N` | | Group of stop places | `NSR:GroupOfStopPlaces:N` | `NSR:GroupOfStopPlaces:N` | | OSM POI | `OSM:TopographicPlace:N` | `OSM:TopographicPlace:N` | | Matrikkel address | bare numeric (e.g. `225678815`) | `KVE:PostalAddress:N` | | Matrikkel street | `KVE:TopographicPlace:KOMNR-NAME` | `KVE:TopographicPlace:KOMNR-NAME` (unchanged) | | Stedsnavn place | bare numeric (e.g. `434810`) | `KVE:PlaceName:N` | | Boundary filter (kommune/fylke code) | bare numeric (e.g. `0301`, `03`) | `KVE:TopographicPlace:N` | | Grunnkrets (in `address.boroughId`) | `whosonfirst:borough:N` | `KVE:Borough:N` (N = 8-digit grunnkretsnummer: KOMNR + 4-digit sequence, e.g. `34200205`) | In v2 **bare numerics on the wire are ambiguous** - they can be stedsnavn places or postal addresses. v3 removes the ambiguity by giving each entity a fully-qualified namespace. ## Response format Both v2 and v3 return a GeoJSON `FeatureCollection`. High-level shape changes: - Feature `properties` use structured objects (`names`, `address`, `transportModes`) instead of v2's flat fields. - A `metadata` object at the top level replaces v2's `geocoding` block. It carries the echoed query, `resultCount`, and an ISO 8601 `timestamp`. Errors come back as HTTP 4xx with an `application/problem+json` body rather than under `geocoding.errors`. - `/v3/reverse` responses include `distance` on each feature, in kilometres with 3-decimal precision (same units as v2). - Features with a real extent (streets, groups of stop places) carry a GeoJSON `bbox` (`[minLon, minLat, maxLon, maxLat]`); point features omit it. The per-property table below is authoritative; see [layers](#layers) and [sources](#sources) for value-set changes on `layer` and `source`. ### Property mapping (`properties.*`) Field-by-field migration. Anything not listed is unchanged; anything marked `_(removed)_` has no v3 equivalent. | v2 | v3 | notes | |-----------------------------|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `id` | `id` | ID shape differs - see [ID format](#id-format) | | `name` | `names.default` | | | `label` | `names.display` | formatted display name with locality context | | `popular_name` | `names.label` | colloquial name; rarely populated today | | `housenumber` | `address.houseNumber` | | | `street` | `address.streetName` | | | `postalcode` | `address.postalCode` | | | `country_a` / `countrycode` | `address.countryCode` | v2 was ISO 3166-1 alpha-3 (`"NOR"`) on `country_a`; `countrycode` was declared but never populated. v3 collapses both into `countryCode` as alpha-2 lowercase (`"no"`). Case-sensitive client comparisons will break silently. | | `county` | `address.county` | | | `county_gid` | `address.countyId` | v2 prefixed `whosonfirst:county:`; v3 returns the raw indexed ID (e.g. `KVE:TopographicPlace:03`) | | `locality` | `address.locality` | | | `locality_gid` | `address.localityId` | v2 prefixed `whosonfirst:locality:`; v3 returns the raw indexed ID | | `borough` | `address.borough` | | | `borough_gid` | `address.boroughId` | v2 returns `whosonfirst:borough:N`; v3 returns `KVE:Borough:N` where N is the grunnkretsnummer (Norwegian sub-municipal statistical unit) | | `city` | `address.locality` | v2 carried both `city` and `locality` for the same value; v3 keeps only `locality` | | `layer` | `layer` | new enum values; see [layers](#layers) | | `source` | `source` | NSR stops normalised: v2 returned `"openstreetmap"` (multimodal parent), `"geonames"` (child), or `"whosonfirst"` (standalone); v3 always returns `"nsr"`. The parent/child/standalone role v2 encoded here is now exposed explicitly in the new `stopPlaceRole` field (next row). `openaddresses` -> `kartverket-matrikkelenadresse`. See [sources](#sources). | | _(new in v3)_ | `stopPlaceRole` | Stop place hierarchy role: `parent` / `child` / `standalone`. Replaces inferring it from the v2 `source` (openstreetmap/geonames/whosonfirst). Set on `stopPlace` features; `parent`/`child` both mean multimodal. | | `category` | `stopPlaceTypes` + `categories` | NeTEx stop place types (e.g. `railStation`) split out from OSM tags (e.g. `restaurant`) | | `mode` | `transportModes` | array of `{ mode, subMode }` objects instead of pair-encoded JSON | | `tariff_zones` | `fareZones` | **not a straight rename**; see below | | `distance` | `distance` | reverse only; kilometres with 3-decimal precision in both v2 and v3 | | `description` | `description` | per-language description. v2 shape: `[{lang: text}, ...]` (array of singleton maps). v3 shape: `{lang: text, ...}` (flat object keyed by ISO 639-2 alpha-3 code) | | `accuracy` | _(removed)_ | Pelias-ism (`point`/`centroid`); not meaningful here | | `gid` | _(removed)_ | the Pelias `source:layer:id` triple; use `id` | | `source_id` | _(removed)_ | duplicate of `id` | | `type` (in properties) | _(removed)_ | always `"Feature"` on the feature itself; the duplicate inside `properties` is gone | `fareZones` is not a straight rename of `tariff_zones`. v3 `fareZones` carries only `AUTH:FareZone:ID`-shaped refs, while v2's `tariff_zones` merged both `TariffZone` and `FareZone` refs for backwards compatibility. `TariffZone` refs are no longer surfaced in v3 responses, and `TariffZone`-shaped values sent as filter input do not match anything. ### Autocomplete example **v2 request:** ``` GET /v2/autocomplete?text=Nationaltheatret&lang=no&size=1&layers=venue ``` **v2 response:** ```json { "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [10.7335, 59.9144] }, "properties": { "id": "NSR:StopPlace:337", "layer": "venue", "source": "openstreetmap", "name": "Nationaltheatret", "label": "Nationaltheatret, Oslo", "category": ["railStation", "metroStation"] } }] } ``` **v3 request:** ``` GET /v3/autocomplete?q=Nationaltheatret&lang=no&limit=1&layers=stopPlace ``` **v3 response:** ```json { "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [10.73350, 59.91440] }, "properties": { "id": "NSR:StopPlace:337", "names": { "default": "Nationaltheatret", "display": "Nationaltheatret, Oslo" }, "layer": "stopPlace", "address": { "locality": "Oslo", "county": "Oslo", "countryCode": "no" }, "transportModes": [{ "mode": "rail" }, { "mode": "metro", "subMode": "metro" }], "stopPlaceTypes": ["railStation", "metroStation"], "source": "nsr" } }], "bbox": [10.73350, 59.91440, 10.73350, 59.91440], "metadata": { "query": { "text": "Nationaltheatret", "limit": 1, "lang": "no", "filters": { "layers": ["stopPlace"] } }, "resultCount": 1, "timestamp": "2025-03-04T11:00:00Z" } } ``` ### Reverse geocode example **v2 request:** ``` GET /v2/reverse?point.lat=59.9110&point.lon=10.7522&boundary.circle.radius=0.5&size=1 ``` **v3 request:** ``` GET /v3/reverse?lat=59.9110&lon=10.7522&radius=0.5&limit=1 ``` **v3 response (abbreviated):** ```json { "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [10.75220, 59.91100] }, "properties": { "id": "NSR:StopPlace:337", "names": { "default": "Nationaltheatret", "display": "Nationaltheatret, Oslo" }, "layer": "stopPlace", "source": "nsr", "distance": 0.012 } }], "metadata": { "query": { "lat": 59.9110, "lon": 10.7522, "limit": 1, "lang": "no" }, "resultCount": 1, "timestamp": "2025-03-04T11:00:00Z" } } ``` --- ## Document: WIP - V3 Migration guide How to migrate from V2 to V3 of the offers API URL: /docs/partner-services/sales-platform/offers/migration-v2-v3 # WIP - V3 Migration guide The required changes from Offer V2 to V3 are relatively minor, compared to the effort needed to migrate from V1. Below is a summary of most changes. ## Spec changes The biggest change is that the spec now only contains the endpoints and models available for partners. Operation Ids have been simplified, new information has been added about security schema and required permissions. Tags have been renamed to be better in line with standards. Error description has been simplified. Headers for rate limiting and Offer expiration have been documented. ## Simple structure changes Some objects have been merged, as they detailed the same information. Some objects have been renamed. Any field referencing TariffZones has been removed. TariffZone is no longer an accepted input. Deprecated fields have been removed. ### Headers | Header | Old value | New value | |---------------------|-----------------------------------|-----------------------------------| | Skip-Offers-Caching | true/false | Replaced by separate endpoints | | ResponseType | SearchResponse/SearchResponseFull | - | | Accept-Language | nob/nno/eng | nb/nn/en per Entur api guidelines | ### Objects | Old name | New name | |----------------------------|-----------------------------| | AvailableFulfillmentMethod | AvailableFulfillment | | PriceSummary | Price | | RefType | ObjectRef | | SearchWithAuthorityRequest | SearchAuthorityRequest | | SearchZonesRequest | SearchGeoLocationRequest | | SearchStopPlaceRequest | SearchGeoLocationRequest | | ZonalValiditySummary | ZonalValidity | ### Fields | Object | Old value | New value | |--------------------|-----------------------------|---------------------------------------------------------------| | ApiError | error | title | | ApiError | message | detail | | OfferSummary | availableFulfillmentMethods | availableFulfilmentMethods (spelling change) | | OfferSummary | - | salesPackageId | | OfferSummary | - | salesPackageVersion | | OptionalProduct | discountRight | discountRights, type change to array | | PreassignedProduct | discountRight | discountRights, type change to array | | PropertiesSummary | - | nuisanceFacilities | | SearchResponse | - | notices | | UnavailableProduct | - | name | | ZonalValidity | - | See [separate description](#redesign-of-geographicalvalidity) | ## Enums Nearly all enum types have been removed, having been replaced by strings. This is to increase flexibility and bring the Offers API more in line with what is returned from JourneyPlanner. Lists of known values will be provided, however the client **must** implement fallback logic to handle unknown values. It is expected that new values will be added during the lifespan of this major version. We do not guarantee a grace period between introducing new values and using them. The only enums remaining are those used as input, as well as those used when categorizing a Recommendation. ### Renaming of enum values To bring Offers more in line with the NeTEx standard, the following Enums have been renamed. Please note this includes both the actual enum used for both requests and string values returned in responses. | Enum name | Old value | New value | |-----------------------|--------------------|-----------------| | UserType | YOUTH | YOUNG_PERSON | | AccommodationFacility | FAMILY_COMPARTMENT | FAMILY_CARRIAGE | | AccommodationFacility | RECLINING_SEAT | RECLINING_SEATS | ## Merging of endpoints The endpoints of `/offers/v2/zones` and `/offers/v2/stop-places` have been merged into one endpoint `/offers/v3/search/geographical-location`. This endpoint supports searching by FareZones, StopPlaces or a mix. The endpoint also supports filtering on transport mode. If the transport mode is absent, all transport modes will be considered unless both StopPlaces are rail stations. The different combinations of inputs in `SearchGeoLocationRequest` are summarized below. | From | To | Result | |-----------|-----------|---------------------------------------------------------------------------------------------------------------------| | FareZone | FareZone | Same behaviour as `/offers/v2/zones` | | StopPlace | StopPlace | Same behaviour as `/offers/v2/stop-places` | | StopPlace | FareZone | Offers will automatically select the `FareZone` from the `StopPlace` with the same authority as the to `FareZone` | | FareZone | StopPlace | Offers will automatically select the `FareZone` from the `StopPlace` with the same authority as the from `FareZone` | ## Redesign of Traveller Several fields on Traveller relating to customer identity and functionality specific to identified individuals were grouped into a new structure `TravellerContext`. `ExistingTicket` on root level was removed, so the client no longer needs to differentiate between one and more travellers, except for `cappingSpecification`. **V2:** ```json { "id": "ID_A", "customerId": "1234567", "productIds": [ "ENT:PreassignedFareProduct:SupplementaryTicket" ], "cappingSpecification": { "customerRef": { "accountBasedTicketingCustomerRef": "ENT:CustomerAccount:12345678" }, "fareContractId": "ENT:FareContract:1234567u8iop", "cappedDiscountRightId": "ENT:CappedDiscountRight:Bestepris" } } ``` **V3:** ```json { "id": "ID_A", "travellerContext": { "customerIdentity": [ { "customerRef": "1234567", "source": "CUSTOMERS" }, { "customerRef": "ENT:CustomerAccount:12345678", "source": "ABT" } ], "ownedRights": [ { "id": "ENT:PreassignedFareProduct:SupplementaryTicket", "zones": ["ENT:FareZone:1", "ENT:FareZone:2"] }, { "id": "ENT:FareContract:1234567u8iop", "cappingSpecification": { "cappedDiscountRightId": "ENT:CappedDiscountRight:Bestepris" } } ] } } ``` ### Customer identity Multiple sources for customer identity are supported. Old fields have been removed. | Old location | New location | |-------------------------------------------------------------------|---------------------------------------------------------------------| | customerId | travellerContext.customerIdentity[].customerRef (source: CUSTOMERS) | | cappingSpecification.customerRef.accountBasedTicketingCustomerRef | travellerContext.customerIdentity[].customerRef (source: ABT) | ### Preowned products ExistingTicket has been moved from root request level to Traveller replacing `productIds` and renamed to OwnedRight. FareContracts should be provided here, and have been removed from `cappingSpecification`, while `cappingSpecification` itself has also been moved into OwnedRight. ## Redesign of GeographicalValidity PointToPointValidity now includes display names for the stop places. `fromPlace` and `toPlace` have been changed from plain strings to named references. ZonalValidity now contains some new fields: `fromZone` and `toZone` with named references, and an _unordered_ set of `viaZones`. FromZone/toZone/viaZones will _not_ be populated when a `groupOfTariffZones` is included. ## Restructure UnavailableProducts UnavailableProducts no longer guarantees the presence of serviceJourney, if that information is not available. This means UnavailableProducts can be returned also from endpoints other than `/offers/v3/search/trip-pattern`. In addition, product name is included for display purposes. ## Notices - Beta Occasionally, some underlying services may not be responding. Previously, that error has been ignored and partial offers have been returned. In order to help clients display information to the customers, a response may include an array of `notices`, describing potentially missing information. Examples include, but not limited to, missing quota, seating or personalisation. It is up to the client to determine if this is useful. ## Recommendations The `recommendations` field in `SearchResponse` has changed from an array of `Recommendation` to a `RecommendationResult` object. Recommendations are partitioned into two lists based on journey coverage. Partial recommendations still carry the `combineWithToCoverEntireJourney` field, describing how to combine them with other recommendations to achieve full journey coverage. The field `id` has been added to `Recommendation`, while `combineWithToCoverEntireJourney` now refers to this `id` rather than a whole `Recommendation`. **V2:** ```json { "recommendations": [{}] } ``` **V3:** ```json { "recommendations": { "coveringEntireJourney": [{}], "coveringPartOfJourney": [{}] } } ``` | Object | Old value | New value | |------------------------------|----------------------------------|----------------------------------| | AccommodationFacility | ANY_FACILITY_SET | ANY | | DurationEnum | - | ANY | | JourneyOrganizeAlgorithmEnum | FOR_EACH_AND_GROUPED | - | | Recommendation | - | id | | RuleSpec | mixinOffersWithHigherFlexibility | mixInOffersWithHigherFlexibility | | RuleSpec | removeSplitRailReplacementOffers | - | ### Default value changes Default values have been updated to reflect the recommended approach. | Field | V2 default | V3 default | |-------------------------------------------|------------|-------------| | RuleSpec.onlyIncludeRecommendedOffers | false | true | | RuleSpec.mixInOffersWithHigherFlexibility | false | true | | RuleSpec.mixInOffersWithOtherFacilitySets | false | true | | RuleSpec.priceComparisonAlgorithm | BEFORE_SDR | TOTAL_PRICE | | CategorySpec.typesOfRecommendation | - | CHEAPEST | | CategorySpec.durationTypes | - | ANY | | CategorySpec.fareClasses | - | ANY | | CategorySpec.facilitySet | - | ANY | ## Behavioural changes ### Searching with existing ticket In Offers V2, if the provided existingTicket referred to a zone not included in the trip, an exception was thrown. This has been changed to evaluating the trip as normal, which removes the necessity of the client knowing whether the previously owned zone is relevant. ### Searching for passed departures Searching for a departure which has passed will now result in an exception (404 Not Found) instead of empty offers. ### Mode for alternative transport When a rail service has been replaced, the actual `mode` will be returned instead of `mode: RAIL` ### Enforcement of api restrictions Multiple travellers in the same request identified with the same customer number will be rejected. Empty arrays are no longer accepted as input in any field. --- ## Document: Open services Overview of Entur's open services. URL: /docs/open-services # Open services :::lead Get access to Norway's public transport network — journey planning, stop places, vehicle positions, mobility, and real-time data. Free and available to anyone, no partnership agreement needed. :::

Access requirements

  • Client identification (ET-Client-Name)
:::info{title="Looking for raw datasets to download?"} Entur also publishes static NeTEx timetable exports, stop place data, and bulk real-time feeds. [Explore Open data](/open-data) ::: ::content --- ## Document: Geocoder Geocoding and reverse geocoding for Norwegian addresses, stop places, and points of interest. URL: /docs/open-services/geocoder # Geocoder :::lead The Geocoder API provides geocoding (text search), reverse geocoding (coordinates to places), and place lookup for Norwegian addresses, stop places, and points of interest. Results are GeoJSON `FeatureCollection`s combining data from the national stop registry (NSR), the cadastre (matrikkelen), Kartverket place names, and OpenStreetMap. ::: Coming from the v1/v2 API? See the [v2 to v3 migration guide](geocoder/migration-v2-v3). ## Endpoints ::endpoint[geocoder/autocompleteV3] ::endpoint[geocoder/reverseV3] ::endpoint[geocoder/placeV3] ## Quick start ```bash # Autocomplete curl -H "ET-Client-Name: company-application" \ "https://api.entur.io/geocoder/v3/autocomplete?q=Oslo+S" # Autocomplete with focus point (boost results near a location) curl -H "ET-Client-Name: company-application" \ "https://api.entur.io/geocoder/v3/autocomplete?q=haugen&lat=59.9&lon=10.7" # Reverse geocode (radius in km, decimals accepted) curl -H "ET-Client-Name: company-application" \ "https://api.entur.io/geocoder/v3/reverse?lat=59.9110&lon=10.7522&radius=0.5" # Place lookup curl -H "ET-Client-Name: company-application" \ "https://api.entur.io/geocoder/v3/place?ids=NSR:StopPlace:337" ``` ## Listing places with filters The `q` parameter is optional on `/v3/autocomplete`. Omitting it while providing at least one filter lists all matching places instead of searching: ```bash # All airports curl -H "ET-Client-Name: company-application" \ "https://api.entur.io/geocoder/v3/autocomplete?stopPlaceTypes=airport" # All stop places in a fare zone curl -H "ET-Client-Name: company-application" \ "https://api.entur.io/geocoder/v3/autocomplete?fareZones=RUT:FareZone:4&limit=50" ``` --- ## Document: Journey Planner Overview of Journey Planner v3, Entur's GraphQL API for public transport routing and departure boards. URL: /docs/open-services/journey-planner # Journey Planner :::warning As of May 1st, 2025, Tariffzones references (e.g. AKT:TariffZone:450) are no longer updated as they are deprecated. You will, however, still get references to FareZones that have replaced the old TariffZones (e.g. AKT:FareZone:2). ::: ## What is Journey Planner? Journey Planner v3 is Entur's core service for journey planning. It uses [OpenTripPlanner](https://github.com/entur/opentripplanner) software to provide departure boards for individual stops, and point-to-point journey planning for all public transport in Norway, including real-time information, regardless of transport mode or operator. All data is presented as a Transmodel-based GraphQL API. **Base URL:** `https://api.entur.io/journey-planner/v3/graphql` **GraphQL IDE:** [https://api.entur.io/graphql-explorer/journey-planner-v3](https://api.entur.io/graphql-explorer/journey-planner-v3) Are you new to GraphQL? You can read more about it here: [https://graphql.org/](https://graphql.org/) ## Authentication Journey Planner is an **Open Service** licensed under [NLOD](https://data.norge.no/nlod/en) and requires the `ET-Client-Name` header for all requests. Use a value that uniquely identifies your company and application, in the form `-` (lowercase, no spaces). For detailed authentication instructions and requirements, see [Authentication](/docs/authentication#open-services). ## API There is only one endpoint: `POST` `https://api.entur.io/journey-planner/v3/graphql` ### Headers - Content-Type: `application/json` - ET-Client-Name: `-` ### Body A JSON body with a `query` field and optionally `variables`. ```json { "query": "string", "variables": { "myVariable": "value" } } ``` ## How does Journey Planner actually work? Journey Planner serves as a backend service for most journey planning apps within the public transport sector in Norway today. This section provides an overview of how the service works and what makes it return travel options for your search. ### Using data from multiple sources To enable multi-modal travel options several datasets are fed into the search engine. #### Static dataset: - OpenStreetMap dataset for all of Norway ([geofabrik.de](https://www.geofabrik.de/)) - Elevation data for all of Norway ([kartverket.no](https://www.norgeskart.no/)) - All Norwegian Stop Places for public transport ([entur.no](https://entur.no/)) - All Timetable data for all Norwegian public transport services ([entur.no](https://entur.no/)) #### Dynamic dataset: - All real-time feeds for Norwegian public transport service ([entur.no](https://entur.no/)) - All available feeds of shared mobility ([entur.no](https://entur.no/)) All datasets and feeds are fed into the search engine which continuously holds an instant representation of the entire public transport network. ### The algorithm for finding the optimal path Any query for a journey between A and B will run the full search algorithm on the current representation. The search algorithm uses the [RAPTOR](https://www.microsoft.com/en-us/research/wp-content/uploads/2012/01/raptor_alenex.pdf) algorithm to find relevant journeys. Broken down, this means the algorithm checks for each minute from the requested search time and looks for Pareto-optimal results. The current implementation checks for pareto-optimality on the following factors: - **Arrival time** - earliest possible arrival is optimal - **Departure time** - latest possible departure is optimal - **Transfers** - fewer is optimal - **Cost** - accumulated value for all elements of a journey; walk paths, transfers, waiting time, time on public transit vehicle, and boarding/alighting a vehicle. Lowest value is optimal Given the above factors, a journey is returned as an option only if the journey is optimal with respect to one of these factors. Additionally, some journeys are filtered out of the returned sets of journeys to avoid obviously undesirable alternatives. ### Neutrality The nature of journey planning is complex and what is considered the "best" option is subjective to the preferences of the end user. The system is designed to try to find a sweet spot for representing travel options as neutral as possible while still providing relevant options to the user. Basing this on calculation of finding pareto optimal paths, given the factors described above, is not perfect, however provides the best collection of travel options in most cases within a reasonable response time. Additionally, the API is rich with parameters to tune your query to achieve desired results, however this is not the default behavior of the service. ### Further reading This document provides a high level description of how the service works. If you want the full details of exactly how the algorithm works, the search engine is open source and you can find the full source code at [github.com/opentripplanner](https://www.github.com/opentripplanner). There are multiple deployments of this search engine around the world and additional information can be found on the project webpage - [opentripplanner.org](https://www.opentripplanner.org). --- ## Document: Partner services Overview of Entur's partner APIs for sales, ticketing, and operator integrations. URL: /docs/partner-services # Partner services :::lead APIs for organisations with a partnership agreement with Entur. It covers timetable management, real-time deviations, ticket sales and settlement. :::

Access requirements

  • Partnership agreement with Entur
  • Client identification (ET-Client-Name)
  • OAuth 2.0 authentication
Entur also provides free public transport data APIs available to everyone. See [Open services](/docs/open-services). ::content --- ## Document: Sales platform Sell tickets for public transport URL: /docs/partner-services/sales-platform # Sales platform :::lead Sell tickets for public transport. ::: ::content --- ## Document: Offers WIP URL: /docs/partner-services/sales-platform/offers # Offers :::note[Under Construction - Coming Soon] ::: [Migration from offers v2 to v3 for partners](offers/migration-v2-v3) [Migration from offers v2 to v3 for internal](/docs/internal/partner-services/sales-platform/offers/migration-v2-v3-internal) --- ## Document: Guides Guides for achieving specific goals in Entur's API ecosystem URL: /guides # Guides Guides will help you achieve specific goals with Entur's APIs by giving you step-by-step instructions. --- ## Document: Intro An overview of clearing concepts and examples for settling financial transactions. URL: /guides/clearing # Intro This document provides examples and surface-level information on generic settlements in the Clearing API. :::note To ensure a robust partner integration, it is therefore recommended to read the in-depth documentation about [Generic Settlements](/guides/clearing/generic-settlements). ::: A generic settlement consists of financial transactions used to distribute money between relevant parties/accounts. The clearing process itself is to ensure: * Data integrity and validation of the settlement and its transactions. * Creation of accounting entries for general ledger and financial reporting. * Documentation for auditing purposes. ## The Clearing API All endpoints in the Clearing API requires an authentication header. To start using the API, you will need a client ID with the correct permissions. Read more in the guide about [Authentication](/docs/authentication#partner-services). Please refer to the [Clearing API documentation](/apis/clearing) for more information about the endpoints used in the examples below. ## Examples ### Minimal settlement This is the minimal required structure to perform a successful clearing of an (empty) settlement: ```json { "distributionChannelRef": "ENT:DistributionChannel:ExternalPSP", "posRef": "EOS:Pos:ExternalPSP", "settlementDate": "2025-11-26", "settlementNo": 1, "genericTransactions": [] } ``` When you submit it to the `POST /settlement-import/generic` endpoint, you will get a response similar to this: ```json { "id": 111122222, "posRef": "EOS:Pos:ExternalPSP", "settlementDate": "2025-11-26", "settlementNo": 1, "externalSettlementNo": 1, "ignoreSequence": false, "comments": [], "status": 0, "statusDescription": "Partner Settlement queued for processing." } ``` This means that Clearing service has accepted the settlement for processing, and put it in queue to be cleared asynchronously. Since no annexes are defined, the clearing will not generate any accounting entries and has therefore little purpose for a partner. It might take some time before the clearing is fully processed. You can check the status by querying `GET /settlement-import/{id}` with the returned `id`: ```json { "id": 11111222222, "posRef": "EOS:Pos:ExternalPSP", "settlementDate": "2025-11-26", "settlementNo": 1, "externalSettlementNo": 1, "ignoreSequence": false, "comments": [], "status": 1, "statusDescription": "100M-Mottakskontroll av oppgjør id=11111222222,ENT:Pos:OsloS1,onr=1,date=25.11.2025,priority=2,batchId=1763981079206 påbegynt 2025-11-25T11:44:39.274030841.\n..." } ``` ### Settlement with a payment annex Settlements consist of the hierarchical elements: Transactions, Annexes, and Parameters. This next example defines a settlement with one transaction of type `ADVANCE`, which contains one annex of type `EOS:Payment:Advance`. This represents an advance payment of 372.00 defined in a `priceContribution`. The in-depth documentation provides more information on the hierarchical structure. When this settlement is cleared, the Clearing service will generate accounting entries. The transaction will be visible in the user interface and relevant financial reports: ```json { "posRef": "EOS:Pos:ExternalPSP", "distributionChannelRef": "ENT:DistributionChannel:ExternalPSP", "settlementNo": 2, "settlementDate": "2025-11-26", "comments": [ {"comment":"This is a comment"} ], "genericTransactions": [ { "transactionType": "ADVANCE", "genericAnnexes": [ { "annexRef": "EOS:Payment:Advance", "attributes": { "paymentType": "AgentVYG", "paymentTypeGroup": "AGENT" }, "priceContribution": { "amount": "372.00" }, "description": "A konto betaling for 3part VY-COIN" } ] } ] } ``` ## Important to remember - The `settlementNo` must be sequentially incremented by 1 per settlement, and the combination of `settlementNo` and `posRef` must be unique. Keeping track of settlement numbers is the responsibility of the partner. - It's worth noting that if previous settlements fail, or if settlements become out of sequence, subsequent settlements will not be processed until all previous settlements are successfully cleared. - Once a settlement is cleared, it cannot be modified or deleted. Any corrections must be submitted through new settlements. Refer to the in-depth documentation for settlement corrections. - The definition of `settlementDate` is partially up to the partner. This could for example be the date the sale was made or the date the settlement is uploaded to Clearing service. However, it's worth noting that setting it to a future date can delay the clearing process if it happens to fall outside the current calendar month. - The annex can be expanded with additional attributes as needed: MVA code, external settlement number, etc. You can for example add a "context" field to the settlement/annex to specify additional information relevant to the transaction. This will not affect the clearing process, but will appear on financial reports that support the specific key. - Comments are supposed to be short and relevant to the settlement/clearing. - It can be assumed that any `4xx` or `5xx` HTTP Code responses when posting a generic settlement, result in the settlement not being saved by the Clearing service for processing. Therefore, the same settlement data can be posted again for a retry. This includes retries on the same `settlementNo` and `posRef` combination. --- ## Document: OMSA Guides Integration guides for partners using Entur's Open Mobility Sales API. URL: /guides/omsa # OMSA Guides This section provides practical, step-by-step integration guidance for Entur's Open Mobility Sales API (OMSA). OMSA is partner-facing and supports the full lifecycle from searching and purchasing to cancellation and refund handling. ## Guide sequence Start with guide 1 and continue in order. - Guide 1: [Search offers](/docs/guides/omsa/search-offers) ## Audience These guides are intended for authorised Entur partners integrating sales functionality in their own channels. --- ## Document: Personnel tickets Overview of the personnel ticket scheme and how to work with it in Entur. URL: /guides/personnel-ticket # Personnel tickets Personnel tickets are a discount scheme in the Norwegian railway industry. The scheme provides reduced fares on train travel for employees and pensioners within participating companies. Family members such as spouses, partners, and dependent children may also be eligible for discounted travel under the personnel ticket scheme, subject to defined eligibility criteria. The scheme is owned by the Norwegian Railway Directorate and managed by Entur. Companies that wish to offer personnel tickets to their employees must enter into an agreement that defines the rules for using the scheme. In Entur, this is handled through the personnel ticket system, which provides an API primarily for internal use. However, some endpoints are also relevant for participating companies and client systems that support the sale of these tickets. To work with personnel tickets, you need to be a partner that has signed the personnel ticket agreement with Entur. This gives you access to the necessary API endpoints and allows you to manage employee data, connect user profiles to personnel ticket rights, and retrieve reports on usage. After having signed the agreement, you can obtain authentication credentials to access the API. A personnel ticket right is also referred to as an entitlement, and the terms are used interchangeably in the documentation. ## How to add and administrate employees Organisations that have signed the personnel ticket agreement with Entur must maintain an updated list of all eligible employees. We therefore expose endpoints for importing updated records of employees: Guide: [How to add and administrate employees through the Personnel Ticket API](/guides/personnel-ticket/1-add-and-administrate-employees). Guide: [How to import employees in CSV format](/guides/personnel-ticket/2-importing-employees-in-csv-format). ## How to connect user profiles with personnel ticket rights For employees to be able to buy personnel tickets, they must connect their personnel ticket right to their personal user profile. Ticket rights are valid for a maximum of one year, or until a change in employee status occurs. Guide: [How to connect user profiles to personnel ticket rights](/guides/personnel-ticket/3-connecting-user-profiles). ## How to use personnel ticket rights in the sales process Supporting the sale of tickets with personnel ticket discounts in client applications involves retrieving available ticket rights for a customer, presenting them to the user, and including the selected entitlement information when requesting offers, so that discounted prices can be calculated. Guide: [How to use personnel ticket rights in the sales process](/guides/personnel-ticket/4-using-personnel-ticket-rights). ## How to fetch tax savings reports Use of personnel tickets for employees of member companies is free of charge up to a limit set by the company. The limit may be set to 0, in which case all personnel ticket travel is considered taxable. If the total annual amount exceeds the company-defined limit, the excess must be reported by the company for tax purposes. Guide: [How to get reports on personnel ticket usage](/guides/personnel-ticket/5-fetching-reports) --- ## Document: Concepts WIP URL: /concepts # Concepts :::note[Under Construction - Coming Soon] ::: --- ## Document: Overview An overview of Entur's open datasets covering public transport timetables, stop places, and real-time data. URL: /open-data # Overview Entur operates the national registry for all public transport in Norway, collecting data from 60 public transportation operators. The registry contains data about 21,000 daily departures on 3,000 routes. This data is open and free of use for app and service developers.