Entur Developer

OSDM

Entur offers a subset of the OSDM specification, version 3.7.1. As of now, only seat reservation for travellers with a travel pass is supported.

Calling the API

Base URLs

Credentials

The API uses OAuth2 client credentials. Your organisation needs access to Entur Partner, where you create the clients yourself.

  1. Go to Entur Partner for the environment you want to use:
  2. Create a new client.
  3. Add role: Klientrolle - Sales channel - OSDM.
  4. Open the client's details page to find Client ID and Client secret.

To get an access token, see Authentication.

Headers

Authorization: Bearer <ACCESS_TOKEN>

Accept-Language: ISO 639-1 language code. Supported: nb (Norwegian) and en (English). Defaults to English if no header is provided.

Requestor: Mandatory header to identify the calling application. We will assign you a "point of sale" and "distribution channel". The header must be a base64 encoded string that contains the following:

JSONCode
{ "entur-pos": "YourPointOfSale", "entur-distribution-channel": "YourDisturbutionChannel" }

ET-Client-Name: Not part of OSDM, but mandatory by Entur on all requests, both open and authenticated. Requests without this header may be rate limited or blocked. Use a value that uniquely identifies your company and application, on the format: company-application (lowercase, no spaces).

Request example

TerminalCode
curl 'https://api.staging.entur.io/bifrost/osdm/reduction-cards' \ -H 'Accept: application/json' \ -H 'Accept-Language: en' \ -H 'Requestor: <REQUESTOR_HEADER>' \ -H 'ET-Client-Name: <CLIENT_NAME>' \ -H 'Authorization: Bearer <ACCESS_TOKEN>'

Supported functionality

ResourceActionPath
OffersPOST/offers
BookingsPOST/bookings
GET/bookings/{bookingId}
FulfillmentsPOST/bookings/{bookingId}/fulfillments
RefundsPOST/bookings/{bookingId}/refund-offers
GET/bookings/{bookingId}/refund-offers/{refundOfferId}
PATCH/bookings/{bookingId}/refund-offers/{refundOfferId}
DELETE/bookings/{bookingId}/refund-offers/{refundOfferId}
Master DataGET/reduction-cards

Searching for offers

  • Search by tripSpecification only, we do not support tripSearchCriteria
  • Reduction card (travel pass) is mandatory. e.g ENT:EntitlementProduct:Intl-Class2
  • Only supported field in offerSearchCriteria is currency (either NOK or EUR)
  • Only supports "embed": ["ALL"]
  • Returns offers without admissionOfferParts, only reservationOfferParts

tripSpecifications[].legs[] must contain enough information so that we can get a match in Entur's journey-planner.

  • stopPlaceRef must be an ID from National Stop Register (NSR) on the format: urn:<nsrRef> e.g. urn:NSR:StopPlace:548 for Bergen
  • timetabledTime of both departure and arrival
  • service.vehicleNumbers[] must only contain one element: the ID of the service journey
  • service.carriers is mandatory in the OSDM spec, but not used since vehicleNumbers[] is a service journey ID. Use an empty array

Search example

We can find stop places from NSR, and use Journey Planner to find trips between them: e.g. query for Bergen stasjon - Oslo S The output will give us serviceJourneyId and timeTabledTime.

JSONCode
{ "tripPatterns": [ { "legs": [ { "serviceJourney": { "id": "VYG:ServiceJourney:64-BRG_444368-R", "expectedStartTime": "2026-09-14T15:38:00+02:00", "expectedEndTime": "2026-09-14T22:27:00+02:00" }, "fromPlace": { "name": "Bergen stasjon" }, "toPlace": { "name": "Oslo S" } } ] } ] }

We can map tripPatterns[].legs[] to tripSpecifications[].legs[], and make a post request against /offers:

JSONCode
{ "tripSpecifications": [ { "legs": [ { "externalRef": "ext-leg-ref-1", "timedLeg": { "start": { "stopPlaceRef": { "objectType": "StopPlaceRef", "stopPlaceRef": "urn:NSR:StopPlace:548" }, "serviceDeparture": { "timetabledTime": "2026-09-14T15:38:00+02:00" } }, "end": { "stopPlaceRef": { "objectType": "StopPlaceRef", "stopPlaceRef": "urn:NSR:StopPlace:337" }, "serviceArrival": { "timetabledTime": "2026-09-14T22:27:00+02:00" } }, "service": { "vehicleNumbers": [ "VYG:ServiceJourney:64-BRG_444368-R" ], "carriers": [] } } } ], "externalRef": "ext-trip-ref-1" } ], "anonymousPassengerSpecifications": [ { "externalRef": "A1", "type": "PERSON", "cards": [ { "code": "ENT:EntitlementProduct:Intl-Class2", "type": "TRAVEL_PASS" } ] } ], "offerSearchCriteria": { "currency": "EUR" } }

Refunds

Subsequent POST requests to /bookings/{bookingId}/refund-offers will always generate new refund offers. Previous offers are still valid, and unused offers don't need to be deleted. The booking will never reflect any proposed refunds, and booking.refundOffers only contains confirmed refund offers.

Last modified on
Did you find what you were looking for?