OSDM Version 3.8 Compliance for Retailer, Distribution and Inventory Systems in Sweden

OSDM Version 3.8 Compliance for Retailer, Distribution and Inventory Systems in Sweden

 


Background

The National Distribution System (NDS), which connects carriers and retailers in the Swedish ecosystem through the OSDM standard, has now been in production for two years.

At the time of implementation, version 3.0 was selected as the “go-to version.”

During these two years, the OSDM standard has evolved and matured, and several systems have adapted to the standard. To remain compliant with the market and to benefit from new functionality, Samtrafiken, together with major stakeholders, has now decided to upgrade to version 3.8.

At this stage, the upgrade does not introduce new functionality. Its purpose is to align NDS with the latest version of the standard and enable future functional enhancements.


Time plan

The upgrade will take place during Q3 and Q4 2026. There will be a six-month transition period during which both versions will be available in parallel. The transition period will start when the new version is deployed in production.

The new version will also be available in the prelive environment to support development and testing. Planned to first week of October.

More details will be communicated to all stakeholders as they become available.

Introduction to the document

This page describes what to do in retailer, distribution and inventory systems connected in the Swedish eco-system.

The first section describes MVP changes that must be handled to be OSDM version 3.8 compliant in the Swedish eco-system.

NB: More changes are on property/item level about nullable, mandatory and minItems. A way to identify these is to run schema validation in IMS and DS to investigate any more formal problems.

To say that the inventory system is 3.8-compliant, more adoptions is needed, but it is up to the provider to serve DS with this information. Also DS need to handle these new endpoints/objects to expose them to retailers. This is stepp 2 stuff in the bottom of the page.

MVP changes (must do)

All existing objects/attributes that are deprecated in 3.8 must be delivered in parallel with the replacement object/attribute

HTTP Header Changes 

Request Headers 

To use OSDM 3.8, all requests must include an Accept header specifying the version: 

Accept: application/vnd.uic.osdm+json; version=3.8 

To make this backward compatible the Accept headers without this, default version 3.0 is assumed

Response Headers 

All responses must include a versioned Content-Type header: 

Content-Type: application/vnd.uic.osdm+json; version=3.8.0 

  • Returning Content-Type with patch version, eg. 3.0.7, is allowed but not mandatory. 

  • A response must not be returned in a different major or minor version than requested. 

Structured Error Handling (RFC 7807)

Errors

Errors are now returned in an extended Problem-object. New attributes are:

  • code

  • pointers

In code, the code of the error is returned. ExampleVALIDATION_ERROR.

In pointers a pointer to the request or response can be returned to point out the element or list item that caused the error.

"problem": { "code": "urn:uic:problem:MALFORMED_REQUEST", "type": "https://osdm.io/errors/malformed_request", "title": "Request failed schema validation", "detail": "The request does not validate the OSDM OpenAPI schema specification", "status": 400, "pointers" : [ { "requestPointer": "#/passengerSpecifications[0]/age" } ] }

The new items are optional, so they might be omitted in responses.

Warnings → Problems

Old warning structure is deprecated and must still be returned together with the new problem structure. Pointers are optional, but it is good practice to return it if possible.

{ "warnings": { "warnings": [ { "code": "NO_OFFERS_FOUND", "type": "https://example.com/warns/no_offers", "detail": "No offers found", "instance": "offers/offer1234" } ] }, "problems": [ { "code": "NO_OFFERS_FOUND", "type": "https://example.com/probs/no_offers", "detail": "Could not find any offers", "pointers": [ { "requestPointer": "#/tripOfferSpecification[0]" } ] },......

problems.code

Code of the error/warning must be returned.

The code shall have an urn-prefix

  • General OSDM error codes urn:uic:problem:[code]

  • Common codes within sweden urn:x_swe:problem:[code]

  • Operator-specific codes  urn:x_swe_VR:problem:[code] . A code specific for carrier VR

Example: urn:x_swe:problem:VALIDATION_ERROR

problems.pointers

To return pointers is optional for the IMS but it is good practice and recommended. Especially to point out the trip in an offer response that has a problem. Then the retailer can explain to the user the reason why offers are missing on some trips.

Passenger Identity (contactDetail)

  • Keep deprecated email and phoneNumber in existing PersonDetail

  • passangerDetail.email also provided inpassengerDetail.contact.email

  • passangerDetail.phoneNumber also provided inpassengerDetail.contact.phoneNumber

Change appliedReductions to CardReference

Offers

  • AdmissionOfferPart.appliedReductionCardTypeis deprecated but shall still be used as is.

  • appliedPassengerTypes.appliedReductions is new and MUST be used from all IMS’s when a discount is applied.

    • code

    • number

    • issuer

    • type

"admissionOfferParts": [ { "summary": "Admission offer part", "appliedPassengerTypes": [ { "passengerRef": "Adult", "type": "ADULT", "description": "Student ST", "tripCoverage": { "coveredTripId": "aedd18a2-9f9c-479f-bb2b-7aac3cbb4b6c", "coveredLegIds": [ "747c6e47-d02e-4bb1-8c79-ce6436d67970" ] }, "appliedReductionCardTypes": [ { "code": "SWE_STUDENT", "issuer": "urn:x_swe:carrier:nnn", "name": { "id": "9d588cc6-f4df-4e94-a238-baf5c7eb3a70", "text": "Student in Sweden" } } ] } ], "appliedReductionCardTypes": [ <-- Depreceated { "code": "SWE_STUDENT", "issuer": "urn:x_swe:carrier:nnn", "name": { "id": "9d588cc6-f4df-4e94-a238-baf5c7eb3a70", "text": "Student in Sweden" } } ] } ]

Booked offers

  • Booked offer parts appliedReductionCardTypeis deprecated but shall still be used as is.

  • appliedPassengerTypes.appliedReductions is new and shall be used and MUST be used from all IMS’s when a discount is applied. .

    • code

    • number

    • issuer

    • type

"admissions": [ { "summary": "booked admission offer part", "appliedPassengerTypes": [ { "passengerRef": "93ac4c8a-aee9-47a8-9b1f-b4660075b806", "type": "ADULT", "description": "Student", "tripCoverage": { "coveredTripId": "aedd18a2-9f9c-479f-bb2b-7aac3cbb4b6c" }, "appliedReductionCardTypes": [ { "code": "SWE_STUDENT", "issuer": "urn:x_swe:carrier:nnn", "name": { "id": "d12fc320-7d15-4959-8710-d230bf13ee93", "text": "Student in Sweden" } } ] } ], "appliedReductions": [ <-- Depreceated { "code": "SWE_STUDENT", "issuer": "urn:x_swe:carrier:nnn", "type": "REDUCTION_CARD" } ] } ]

Deprecated confirmabelUntil

Retailer uses booking.confirmationTimeLimit instead.

IMS continues returning deprecated confirmableUntil.

Provisional refund amount

To avoid negative provisionalAmount a new attribute booking.provisionalRefundAmount is added. It describes the refund amount the customer is entitled to. provisionalAmount is 0 when provisionalRefundAmount is set

Allow fulfillments in prebooked state

This is already the case for SJ-bookings. Probably nothing to do.

Deprecate fulfillment media type ALLOCATOR_APP

ALLOCATOR_APP is replaced with DISTRIBUTOR_APP and RETAILER_APP . All three must be handled.

Deprectate isReservationRequired

AdmissionOfferPart.isReservationRequired and Admission.isReservationRequiredare deprecated.

Use minGroupItemsToBeBooked in reservationRelation instead. Both in offers and bookedOffers.

Deprecated appliedReductions on admission level

For retailers, stop using appliedReductions on offer part level. Use appliedPassengerTypes.appliedReductions instead. IMS need to provide both.

Add graphical reservation indicator for booking context

For offers: reservationOfferPart.supportedPlaceSelectionFlows is added to indicate how places can be selected or not.

For booking: reservations.supportedPlaceSelectionFlows is added to indicate how places can be selected or not.

  • MANUAL_PLACE_SELECTION_WITH_FEE: Manual/graphical place selection. A seat selection fee is charged for certain places. /availabilities/vehicle-place-map must be called before the /bookings call.

  • MANUAL_PLACE_SELECTION_WITHOUT_FEE: Manual/graphical place selection. No seat selection fee is charged for certain places. /availabilities/vehicle-place-map must be called before the /bookings call.

  • AUTOMATIC_PLACE_SELECTION: Automatic place selection based on selected accommodation (sub) types and place properties (see BookingRequest.placeSelections[].accommodations[]). It is not necessary to call /availabilities/* before the /bookings call.

  • AUTOMATIC_PLACE_SELECTION_NEARBY: Automatic place selection nearby a given place. /availabilities/nearby must be called before the /bookings call.

  • AUTOMATIC_PLACE_SELECTION_PREFERENCES: Automatic place selection based on available place preferences. /availabilities/preferences must be called before the /bookings call.

Setmap corrections

Ignore isSelectable on PlacePossition, use status istead to know if a place is FREE or not.

isSelectable stays on compartment level for complete compartment sales.

zOrder in LayoutCoordinates

layouts.places.coordszOrder is changed from string to integer. Breaking and must be handled for all parties.

Compartment number

booking.bookedOffers.reservations.placeAllocation.reservedPlaces.compartmentNumber is new and can be used to identify compartments when making complete compartment reservations.

compartmentNumber: description: | Compartment number as indicated at the compartment in the coach. A compartment number must be set if the compartment is selectable as a whole only. type: - string - 'null' examples: - "C1" - "6" - "61-66"

New end-point PATCH /bookings/{bookingId}/passengers (Added 2026-05-18)

This endpoint is not mandatory in MVP, but very desirable for IMS’s to implement.

To make bookings for large travel parties easier, there is a need for retailers to implement this bulk-update endpoint. Today, the client must call DS once for each passenger when adding personal details to the booking. This can take a long time and causes timeouts for large bookings. 

The endpoint takes a list of passenger details and updates all passengers in one call.  

It is desirable that all IMS systems have this end-point available from the beginning since DS will not take the list of passengers and make individual calls for each passenger to an IMS system.  

Refund offer breakdown (Added 2026-05-18) 

To enable informative UX at refund, retailers ask for the refundOffers.refundOfferBreakdown.  

With refundOfferBreakdown, it is possible to show the purchaser/agent the refund value on each bookedOfferPart in the booking including fees. 
 

DS and Samtrafiken IMSs can already handle refundOfferBreakdown, but call it refundOfferBreakDown. This must be corrected in version 3.8. 
 

{ "refundOffers": [ { "id": "779bcf1d-ef26-4ccb-b4c5-fcf1f7167015", "summary": "Refund offer", "createdOn": "2026-05-18T09:47:44.7966748Z", "validFrom": "2026-05-18T09:47:44.7966748Z", "validUntil": "2026-05-18T09:57:44.7966748Z", "status": "PROPOSED", "refundOfferBreakdown": [ { "refundFee": { "vats": [ { "countryCode": "SE", "amount": 538, "scale": 2, "percentage": 6.0 } ], "currency": "SEK", "amount": 9500, "scale": 2 }, "refundableAmount": { "vats": [ ], "currency": "SEK", "amount": 0, "scale": 2 }, "bookingParts": [ { "id": "d182f9b4-654e-43f4-a09c-bb961e68b56d" } ], "fulfillmentId": "d182f9b4-654e-43f4-a09c-bb961e68b56d" } ] } ] }

Step 2

To say that the system is OSDM version 3.8 compatible these parts must be taken care of.This is not needed to go live but is critical for DS to update soon after launch or simultaneously. Underlying IMS may have these features and want to propagate them to retailers.

Add GrantedReductionAmounts

To make it possible for the retailer to show in detail the discounted amount of each reduction-type in the offer/booking.

Add grantedReductionAmounts in offers parts and booked offers parts for admission, reservation and ancillary types.

Relation between fulfillment and leg

Make it possible to point out fulfillment on leg-level for through fare admissions .

TripCoverage is added to fulfillment to makt his clear.

image-20260223-121628.png

Allow fulfillments without content

When the distributor generates the document on behalf of the provider.

A new attribute to the fulfillment is added contentComplete. The attribute indicates whether the fulfillment has all documents or parts generated (if any needed) or they are still pending generation.

Add selection fee to seat map

To make it possible to show an extra fee for specific compartments/seats in the placemap a selectionFee attribute is added to Compartment and PlacePosition.

Support for coach deck layouts

New endpoints is created for place-map. These end-points is currently not used but shall be available to be 3.8-compliant. Important is that deprecated end-points keep working.

  • GET /coach-deck-layouts

  • GET /coach-deck-layouts/{layoutId}

  • POST /availabilities/vehicle-place-map

Migrating seat map to version 3.8 is subject to further investigation.

Generalize add/remove reservations and ancillaries

Currently there are separate endpoints to manage reservation and ancillary offerParts. Two generalized endpoints replaces four endpoints in the old specification

  • POST /bookings/{bookingId}/booked-offers/{bookedOfferId}/offer-parts

  • DELETE /bookings/{bookingId}/booked-offers/{bookedOfferId}/offer-parts

  • Depreacted /reservations and /ancillaries

Important that deprecated endpoints keep working as today.