This is the E2E documentation for the SBB Swiss Mobility API (B2P API) which describes the concepts, services, booking flow, access, authorization and error handling.
The services are described briefly from the business perspective. The technical details of the services (methods, request, responses, mandatory parameters etc) and a service mock are available on the Swagger UI page:
|
1. Registration
The B2P web service is secured by an API Management Platform. To get access to the services you need to register as a developer on the SBB developer portal. There is also an integration developer portal that may be used for testing purposes. Please first register for the integration environment.
Before you will get access to the production environment you need to successfully integrate the services on the integration environment to show compliance with the rules.
For logging into the developer portal you need to have an account at one of the following provides:
-
Azure (only for internal use)
-
Swisspass
-
GitHub
-
Google
-
Microsoft
When logging in with one of these identity provides you will be asked to share a minimum of information like your e-mail address. Once registered you will find the B2P API as following:

As a first step you need to choose a plan. The plan defines usage limits and which services you are allowed to call. All plans need SBB approval. The plans can be changed later (needing additional approval).

When registering your Client, you will be asked for a name and description. Those values can be chosen freely,
but we recommend you to use something descriptive. Choose authentication provider "Azure AD". Once you finished
the registration process your client should be in a Pending state until it gets activated by the SBB. Even
though it is not activated yet you can already see your login credentials. Since the B2P web service uses the
OAuth 2 client credentials flow you will get a Client ID
, a Client Secret
and a scope
. There is no need to
provide a Redirect URL.
Before you can start using the web services you need to contact SBB to get your personal contract ID that has to be send with every request.
Please note that the Swagger UI within the developer portals are for documentation purposes only. When expecting mocked responses one should use the ![]() |
2. Authorization
The B2P web service is secured using OAuth 2. Therefore, you need to obtain a token before sending requests to one of the services. All auth tokens are valid for 60 minutes and should be reused for subsequent requests. We recommend you to use existing libraries for your implementation, but to validate your credentials and to do some initial tests you can use a tool like Postman or Curl. The first step is to obtain a token (JWT) and to set it as a header in your actual request. For obtaining a token you need your Client ID and Client Secret (see Registration). You can obtain the token from:
Refresh tokens are not supported. |
https://login.microsoftonline.com/2cda5d11-f0ac-46b3-967d-af1b2e1bd01a/oauth2/v2.0/token
curl -X POST \
'https://login.microsoftonline.com/2cda5d11-f0ac-46b3-967d-af1b2e1bd01a/oauth2/v2.0/token' \
-d 'grant_type=client_credentials&client_id=$clientId&client_secret=$clientSecret&scope=$scope'
The token is encapsulated within the result as an access_token
and needs to be set as a Bearer token
in the Authorization-HTTP-Header as following:
curl -X GET \
'https://b2p.api.sbb.ch/api/locations?name=Bern' \
-H 'Authorization: Bearer $accessToken' \
-H 'Cache-Control: no-cache' \
-H 'Accept: application/json' \
-H 'X-Contract-Id: ABC1234' \
-H 'X-Conversation-Id: e5eeb775-1e0e-4f89-923d-afa780ef844b'
The URL for the B2P production environment is https://b2p.api.sbb.ch whereas the integration environment is available under https://b2p-int.api.sbb.ch. |
3. General Concepts
3.1. Web Service
The B2P web service is a RESTful web service that uses HTTP methods for accessing resources.
The following parameters must be set in the HTTP Header with every request:
-
The Conversation-ID (
X-Conversation-Id
) to identify the current sales process -
The partner’s contract ID (
X-Contract-Id
) to identify the partner, permissions and preferences
curl -X GET \
'https://b2p.api.sbb.ch/api/locations?name=Bern'
-H 'Accept: application/json' \
-H 'Accept-Language: en' \
-H 'X-Conversation-Id: cafebabe-0815-4711-1234-ffffdeadbeef' \
-H 'X-Contract-Id: ABC1234'
3.2. Conversation-ID
The Conversation-ID
is an unique identifier of a sales process. Every step (get offers, booking, get tickets, etc.) within one sales process must share the same Conversation-ID
.
The Conversation-ID
is a mandatory parameter and must be send in the HTTP header as X-Conversation-Id
with every request.
The |
It is crucial that a new |
If however the user requests multiple offers and multiple prebookings the Conversation-ID should be reused, as he is still in the same sales process.
|
3.3. Versioning
The services are versioned and the service version can bee seen in the URL. No visible version means it’s V1. Example:
-
Prebooking Version 1: https://b2p.api.sbb.ch/api/prebookings
-
Prebooking Version 2: https://b2p.api.sbb.ch/api/v2/prebookings
The services are versioned independently of each other. It’s unproblematic for example to use Prebooking V1 together with Booking V2.
Service versions that aren’t published on the production environment but only on the integration environment are subject to change. As soon as a version is available on the production environment there won’t be any breaking changes. However, it’s possible that optional request or response parameters will be added.
The general rule is that there may be a new version every 3 weeks and old version may be removed from the API after 9 weeks. |
3.4. Links
Most services return links to guide you through the booking flow and tell you which services can be called next.
Here is an extract from a trip-offers
response.
"links":
[
{
"rel": "prebook", (1)
"version": 2, (2)
"href": "https://b2p.api.sbb.ch/api/v2/prebookings", (3)
"method": "POST", (4)
"contentTypes": [
"application/json" (5)
]
},
{
"rel": "online-offers",
"version": null,
"href": "https://www.sbb.ch/de/kaufen/pages/fahrplan/fahrplan.xhtml?[...]", (6)
"method": "GET",
"contentTypes": [
"text/html"
]
}
]
1 | Name of the service. |
2 | Version - if the service is versioned. |
3 | Service URL. |
4 | HTTP Method. |
5 | Returned media type. |
6 | This link redirects the user to the SBB webshop to perform the next steps. |
Placeholders
Links may contain placeholders that must be filled in. Below is an example of a trip response.
{
"rel": "trip-offers",
"version": null,
"href": "https://b2p.api.sbb.ch/api/trip-offers?tripId=qgTwSQoCVjESxgLCtkhLScK2VCRBPTFATz1aw7xyaWNoIEhCQFg9ODU0MDIxMUBZPTQ3Mzc4MTc3QHU9MEBMPTg1MDMwMDBAYT0xMjhADTswQmVybkBYPTc0MzkxMwU1GDY5NDg4MzQZNQQ3MBk1LDIwMjMwMjExMTAzMhkNPDEyOCRJQyAxIDcxNCQkMSQFAeDCtktDwrYjVkUjMiNDRiMxMDAjQ0EjMCNDTSMwI1NJQ1QjMSNBTSMxNjQ2NSNBTTIjMCNSVCMxNSMBOQ06KDAjRVJHIzEjSElOAQwgQ0sjOTI3OTJ8EQYQODQ4fDkFBhQwfDB8ODUFGSQwfDF8MHw0MTE0BRY8LTIxNDc0ODM2NDgjwrZLUhFcLDEjGtoBCjoKEgoHOCkauBIHU1RBVElPThIZMjAyMy0wMi0xMVQxMDozMjowMCswMTowMCIHUExBTk5FRCgIFTwhIRU8ABoyPAAMMToyOEo8APBAChIYCAgQChoGMDAwMDExIgJJQyoBMTIDNzE0GjYKAlIgEhpQbGFjZSByZXNlcnZhdGlvbiBwb3NzaWJsZRj___8JAgQBIAkITP___wEqDlBVQkxJQ19KT1VSTkVZ&passengers=${passengerInfos}",(1)
"method": "GET",
"contentTypes": [
"application/json"
]
},
{
"rel": "online-offers",
"version": null,
"href": "https://www.sbb.ch/de/kaufen/pages/fahrplan/fahrplan.xhtml?recon=VCUyNEElM0QxJTQwTyUzREJlcm4lNDBYJTNENzQzOTEyMiU0MFklM0Q0Njk0ODgyNSU0MEwlM0Q4NTA3MDAwJTQwYSUzRDEyOCU0MCUyNEElM0QxJTQwTyUzRFolQzMlQkNyaWNoK0hCJTQwWCUzRDg1NDAxOTMlNDBZJTNENDczNzgxNzclNDBMJTNEODUwMzAwMCU0MGElM0QxMjglNDAlMjQyMDE4MDgyMzEwMzIlMjQyMDE4MDgyMzExMjglMjRJQysxKysrKyUyNCUyNDElMjQlQzIlQjZLQyVDMiVCNiUyNTIzVkUlMjUyMzAlMjUyM0NGJTI1MjMxMDAlMjUyM0NBJTI1MjMwJTI1MjNDTSUyNTIzMCUyNTIzU0lDVCUyNTIzMSUyNTIzJUMyJUI2S0NDJUMyJUI2JTI1MjNWRSUyNTIzMCUyNTIzRVJHJTI1MjMxJTI1MjNISU4lMjUyMzAlMjUyM0VDSyUyNTIzMzcyMTUyJTI1N0MzNzIxNTIlMjU3QzM3MjIwOCUyNTdDMzcyMjA4JTI1N0MwJTI1N0MwJTI1N0M4NSUyNTdDMzcyMTQyJTI1N0MxJTI1N0MtMjE0NzQ3OTUzNCUyNTdDMCUyNTIz&datum=2018-08-23&zeit=1032",(2)
"method": "GET",
"contentTypes": [
"text/html"
]
}
1 | Link with the ${passengerInfos} placeholder that must be filled in with passenger information. |
2 | URL without placeholders. The link points to the www.sbb.ch website, where the passenger information will be entered by the user. |
Message Body and optional parameters
Neither the body of a POST request nor the optional parameters are shown in the links. The body structure and the optional parameters can be seen in the Swagger UI.
curl -X GET \
'https://b2p.app.sbb.ch/api/trip-offers?tripId=zwVECgJWMRLSAsKswrZCQUlNwrZ0AQvwQEhLScK2VCRBPTFATz1CYXNlbCBTQkJAWD03NTg5NTY2QFk9NDc1NDc0MDhAdT0wQEw9ODUwMDAxMEBhPTEyOEAkDToIZXJuATUUNDM5MTMxATUYNjk0ODgzNBk1DDcwMDARNSwyMDIzMDIyNDE3NTYZDTg4NTYkSUNFIDM3MSQkMSQFAeDCtktDwrYjVkUjMiNDRiMxMDAjQ0EjMCNDTSMwI1NJQ1QjMSNBTSMxNjQ2NSNBTTIjMCNSVCMxNSMBOQ06KDAjRVJHIzEjSElOAQwgQ0sjOTE3OTZ8EQYEODUBDAEGGDB8MHwxNjUFGiQ0fDF8MHw0MTE0BRc8LTIxNDc0ODM2NDgjwrZLUhFdLDEjGvMCCjoKEgoHOCkawBIHU1RBVElPThIZMjAyMy0wMi0yNFQxNzo1NjowMCswMTowMCIHUExBTk5FRCgQCh8VPAQyMxU8ACIVIQARGSEIMjE4SiEAJBIKGwoOCgMxMzJKHQAAExWbIYAVIQAaMpsAADhWmwDwQxQSFggQEBQaBjAwMDAxMSIDSUNFMgMzNzEaOgoCVlISHkJJQ1lDTEVTOiBSZXNlcnZhdGlvbiByZXF1aXJlZBj_____BQMEASAFBwEBQAEaNgoCUiASGlBsYWNlIHJlGTgccG9zc2libGVWOAA8Kg5QVUJMSUNfSk9VUk5FWQ%3D%3D&passengers=paxa%3B42%3Bhalf-fare' \
-H 'Accept: application/json' \
-H 'Accept-Language: en' \
-H 'X-Conversation-Id: cafebabe-0815-4711-1234-ffffdeadbeef' \
-H 'X-Contract-Id: ABC1234'
3.5. Swagger documentation & Service Mock
The services are described in detail using Swagger. The Swagger UIs are available here:
Swagger UI Integration (Preview of upcoming features)
Swagger describes every service, its request and response parameters and possible errors.
In addition, we have implemented a service mock. It does not call the real backend but returns a predefined response. You can click Try it out! in the Swagger UI to play around with the services and get an idea how they work.
4. Sales process
The sales process is a sequence of steps in the booking flow as shown in the figure below.
The sales process typically begins with the offer requests, however there may be some previous steps needed to perform the offer request depending on the offer request type.
There are three offer request types that initiate a sales process:
- Route based
-
Offers for a specific origin and destination will be returned. See Route Offers for details.
- Trip based
-
Offer for a specific trip (i.e. train connection) will be returned. See also Trip Offers and Group Trip Offers for details.
- Product based
-
Offers for a specific product will be returned. See Product Offers and Group Product Offers for details.
Payment step can be omitted by all non retailers. See Payment for details. |
4.1. Offers
Trip Offers
The B2P Service operation to retrieve offers based on a given tripId for individual travelers.
Please use the B2P trips service operation to get the required tripId .
|
The system calculates and returns only the best offers (in terms of service and price) that match the traveler wish.
The returned offer may be different for each traveler depending on its age or reduction card. For example, a request with two travelers, one adult and one child, may result in an offer container with two offers; city ticket for the adult and a day pass for the child.
With the addition of the travelers dogs and bikes, passengers is not a required field for trip offers anymore. However either one of the dogs, bikes or passenger must be set. Otherwise a request-parameter-invalid problem will be returned. In contrast to the passengers, a dog or a bike is only requested with an id.
See trip-offers-controller for details.
Special Cases:
You will be able to sell 1 day travelpasses. These passes can be returned as an offer at trip-offers in the case a 1 day travelpass is cheaper than a regular ticket. In case you offer your client to search for return trips be aware of this:
Example: March 15 Zurich – Geneva, regular fare CHF 100.00 March 15 Geneva – Zurich, regular fare CHF 100.00
1 day travelpass CHF 80.00 You have to ensure that you don’t sell a daypass per way!
Not for every journey it is possible to sell a regular ticket (productID 125). For journey within a network (association) you have to sell a “network fare”. Nor regular tickets will be offered via our API. There exists separate products per network (for ex. productID 1560 for unireso network). The logic of the sales process is exactly the same as for the regular ticket but the validity of these tickets are different.
In some cases there will be information on trip conditions. For example in case of construction work.
Group Trip Offers
The B2P Service operation to retrieve offers based on a given tripId for traveler groups.
Group trip offers work in the same way as the regular trip offers, except that you can request offers for groups of 10 or more travelers. The offered products will be group tickets.
Affiliate links are not supported for group trips.
See trip-offers-controller for details.
Product Offers
The B2P Service operation to retrieve offers for a given productId for individual travelers.
Some offers do not require a trip. These can be sold using the product-offers service operation.
The product-offer request requires a productId
and returns only offers with the requested product.
The productId
for a specific product can be obtained via the B2P products service.
Some Products do not need a passenger to be provided at the offer step (e.g. dog day-pass, bicycle day-pass). Those products can be identified easily, as there is no customer segment with the travellerType person defined. However, at the prebooking step the passenger has to be provided. |
With the addition of the travelers dogs and bikes, passengers is not a required field for product offers anymore. However either one of the dogs, bikes or passenger must be set. Otherwise a request-parameter-invalid problem will be returned. In contrast to the passengers, a dog or a bike is only requested with an id.
See product-offers-controller for details.
Group Product Offers
The B2P Service operation to retrieve offers for a given productId for traveler groups.
Group product offers work in the same way as the regular product offers, except that you can request offers for groups of 10 or more travelers. The requested product must be a group ticket. You can check which customer segments can be selected for a product using the products service.
See product-offers-controller for details.
Route Offers
The route offer request is similar to the trip offer but does not require a tripId
.
Instead the UIC code of the origin, destination (and via) must be provided.
The UIC codes can be obtained from the location service.
Note that supersaver tickets are never returned for the route offer request, because supersaver tickets are bound to a specific train (and so to a tripId ).
|
With the addition of the travelers dogs and bikes, passengers is not a required field for route offers anymore. However either one of the dogs, bikes or passenger must be set. Otherwise a request-parameter-invalid problem will be returned. In contrast to the passengers, a dog or a bike is only requested with an id.
See route-offers-controller for details.
Offer Options
There are several flags for controlling the way how offers are bundled and filtered in the backend. Those flags do not appear on the API documentation, as they are not part of the business requirements but only exposed for special purposes. At the moment the following options can be set as HTTP headers when requesting offers (if not set the default behaviour is used):
-
X-Offer-Options-Disable-Business-Filters [TRUE/FALSE]: This options force disables the offer filter logic of the backend. By default unuseful offers are dropped and not send in the B2P response e.g. as they may be too pricy for the requested journey. By setting this option to TRUE no offers will be dropped by the backend.
-
X-Offer-Options-IP-Extension-Ticket [TRUE/FALSE]: This option can be set when requesting specifically for international connection tickets. Please note that this behaviour has to be enabled per contract.
4.2. Prebookings
Offer prebookings
General
The offers-prebooking service makes an 'exclusive reservation' of an offer for the user until he finishes the booking process. It is especially important for limited offers such as supersaver tickets and seat reservations (not yet available via web services).
The message body structure for the prebooking can be seen in the prebookings-controller.
Passenger
Note that the id
of the passenger in prebooking request, must be identical to the passenger id in the offer request:
{
"passengers": [
"PaxId1;33;half-fare" (1)
],
"validFromDate": [
"2021-05-21"
],
"validFromTime": [
"14:52"
]
}
[{
"offerPrebookings": [{
"offerIdentifier": "6575552"
}],
"passenger": {
"id": "PaxId1", (1)
"firstname": "John", (2)
"lastname": "Doe", (2)
"dateOfBirth": "1988-05-18" (3)
}
}]
1 | The passenger id cannot change between offer request and prebooking request and is limited to 50 characters. |
2 | The firstname and lastname are limited to 30 characters. |
3 | The dateOfBirth must reflect the age of the passenger from the offer request. |
Dog and Bike
When requesting offer prebookings for dogs and bikes, the id of the dog/bike object must match the id of the dog/bike from the offer (1). Additionally there has to be set an owner for dog/bike in the prebooking offers request (2).
{
"bikes": [
"BikeA" (1)
],
"validFromDate": [
"2022-08-21"
],
"validFromTime": [
"14:52"
]
}
[{
"offerPrebookings": [{
"offerIdentifier": "6575552"
}],
"bike": {
"id": "BikeA", (1)
"owner": { (2)
"firstname": "John", (3)
"lastname": "Doe", (3)
"dateOfBirth": "1980-05-20" (4)
}
}
}]
1 | The dog/bike id is limited to 50 characters. |
2 | The firstname and lastname are limited to 30 characters. |
3 | The dateOfBirth must reflect the age of the owner. |
Group Offers
Although group trip/product offers are requested for passenger groups instead of individual passengers, a passenger must still be given when prebooking the group offer. This passenger will be the contact customer for the journey, their name may be shown on the ticket. The passenger ID may be chosen freely.
Group offers typically require a GRUPPENNAME
(group name) sales parameter. The group name may be chosen freely by the customer. It is shown on the ticket. The group offer response will contain the GRUPPENNAME
sales parameter if it is required. In this case, the value must be given as part of the prebooking request.
[{
"offerPrebookings": [{
"offerIdentifier": "6575552",
"salesParameter": {
"GRUPPENNAME": "Example Group Name" (1)
}
}],
"passenger": {
"id": "PaxId1", (2)
"firstname": "John",(3)
"lastname": "Doe",(3)
"dateOfBirth": "1988-05-18"
}
}]
1 | The group name is limited to 30 characters. |
2 | The passenger id is limited to 50 characters. |
3 | The firstname and lastname are limited to 30 characters. |
4.3. Payment
Prior to booking, the payment step prepares the payment of one or more prebooking ids. This step is mandatory for all retailers.
The B2P web service currently supports two kinds of payments:
-
Invoice payment (is the payment method for all retailers)
-
Partner uses their own payment process (non retailers)
Invoice payment
The invoice payment will trigger an invoice that will be sent to the partner / retailer. Starting from version 2 of the payment service there are two optional reference fields available that may be set to internal references.
Only Swiss Francs (CHF) are accepted in payment. |
See payments-controller for details.
4.4. Booking
After an offer (or offers) was prebooked (and the payment was successful) it can be booked.
The api requires a list of preBookingIds
to be sent as an array in the body of the POST request and returns
one bookingId
plus a section for each preBookingId
the corresponding ticket as the ticketId
.
See the bookings-controller for details.
The booking response might take up to 25 seconds. If needed, retries should be configured on client side after at least 30 seconds. |
4.5. Changes in booking v2
In v2, a booking status can be sent when booking a prebooking. This can be either "PENDING" or "COMMITTED".
Example:
{ "prebookingIds": [1234], "status": "PENDING" }
Status COMMITTED
If no status is sent, or the status "COMMITTED" is sent, the booking behaves as in v1.
Status PENDING
If the status PENDING, a booking can be deleted up to 20 minutes after it has been booked.
This can be done over the delete-booking call.
A booking can be confirmed earlier instead of waiting for the 20 minutes to pass until the booking is automatically moved to the status CONFIRMED.
Use the patch-booking call to confirm a booking manually.
This confirming is entirely optional, as the system will automatically confirm the booking if neither a deletion nor a confirmation is sent. Do note the limitation below though. |
A booking in a PENDING state cannot be refunded through the aftersales refund. Only bookings in a COMMITTED state can be successfully refunded. |
Please be aware of the impact to flex products: The activation of the single travel days can not be done while the booking is PENDING state. |
4.6. Fulfillment
After the successful booking, the tickets can be downloaded.
All tickets are available for download until one year after travel or latest validity date. |
Tickets are available in several formats. Just define the accepted format as HTTP header information, i.e. "Accept":
"application/pdf"
to get a PDF.
We recommend to download all available formats and cache them on your side.
Content type | Ticket type |
---|---|
application/pdf |
PDF (client needs to print the document) |
text/html |
Screen Ticket (client can show the ticket on his device or print it) |
application/vnd.apple.pkpass |
Wallet (to store in a mobile wallet vault) |
The bookingId
and the ticketId
must be provided in the url path to download the ticket.
See the bookings-controller/getTicketUsingGET for details.
Please note that not all ticket types are available for every booking. The booking response provides the information which ticket types are downloadable. |
4.7. Additional services
Master data
Networks
The B2P web service supports the following services to query information about Swiss railway networks.
-
/api/networks allows to fetch the list of available swiss railway networks. The response contains a list of the available networks including a link to query the network details.
-
/api/networks/{networkId} allows to fetch the network details for a given network. The response contains the name and description of the network and a list of the network zones.
-
/api/networks/{networkId}/zones allows to fetch the list of network zones for a given network. Please refer to the network zone map of the railway company to locate the zone geographically.
See networks-controller for details.
Products
The B2P web service supports the following services to query information about offered products.
-
/api/products allows to fetch a complete list of supported products.
-
/api/products/{productId} allows to fetch product details for a given productId. These details include the available customer segments for a product as well as the offer-entrypoints that may be used.
See products-controller for details about the returned data.
Journey services
Locations
The location service is used to perform a pattern-based search to retrieve a list of matching locations of type STATION in the journey planner database. The result is a possible match of (train-, bus-, tramway-) stations with corresponding UIC codes (standard ID-type for Switzerland) and coordinates.
To get an initial list of all possible stations please visit the public transport page https://opentransportdata.swiss/en/organization/oevch
and download the newest Timetable xxxx (GTFS) zip file. Unpack it and use the stops.txt CSV file. Inside the file you can ignore the stops, where a
parent station is given and import the parent station itself with the stop_id but without the trailing P . Further you need to remove the possible
duplicated entries for the stop_id . Be aware that the stop list will be updated +/- weekly. So it is suggested to updated the initial stop list on
a regular base.
|
See locations-controller for details.
Trips
The trips service returns different trips (concrete journeys from the viewpoint of a passenger planning his trip) for a specified origin and destination (and via). The response body of the trip request contains some navigation links indicating the next services you can call. All journeys rely on a yearly plan (usually changing in first decade of December). Each Segment means a separate transport-product (by means passengers need to change at the ending Stop of a Leg). The underlying system provides a default change time when passengers need to switch transport-products. The underlying system handles date/time requests in Swiss timezone "Europe/Zurich" (seconds are irrelevant). If you’re interested in real-time data, you can find additional information here.
See trips-controller for details.
Prices
The B2P web service prices operation allows to query the cheapest prices for a given trip.
Use the trips service to retrieve the (required) tripId .
|
A price offer cannot be used for prebooking and indicates the best price only.
By default the service assumes that the traveler is an adult with half-fare reduction card. The price offer can be based on a regular fare or (if available) a super saver fare. Starting from V2 the traveler details may be specified when requesting prices to overwrite the defaults.
See prices-controller for details.
There may be multiple tripIds specified in one request to fetch multiple price quotes at once. |
To avoid breaking the look-to-book ratio between offers and bookings, we recommend using this services for requesting simple price information and to only use the trip offers service after the user chose a specific trip. |
Barcodes
The service is used to generate the barcode for the public transport platform (German "öV-Platform"), which is part of the interface NOVA Control (German "NOVA Kontrolle"). This service allows authorized callers for producing barcodes (2d-codes and textcode). These barcodes can be validated by control devices using one of the control applications of the öV-CH (either the "KoServ app" running on Android or one of the "KoServ kernels" (or KSK)). The barcode produced are conform to the e-Ticketing concept.
The barcode service generates a barcode from a collection of attributes which are passed by the caller. The attributes have a type and a semantic attached to them. Most of the attributes are optional. The barcode is generated on the base of the attributes which are effectively passed. The validation of the barcode by the control application exploits the semantic of each attribute in order to compute the validity of the ticket.
A barcode can be deleted using its barcodeId, which cancels it in KoServ and invalidates it for subsequent controls.
See barcodes-controller for details.
5. After sales process
In some situations, the booked ticket has to be refunded or cancelled for various reasons (technical errors, sickness, wrong ticket, change of plans or others). To address this, the B2P web service offers an aftersales functionality.
The aftersales flow (often referred as a SAV process, French "service après-vente") is shown in the figure below.
5.1. Booking data
The booking data services provide information about the booking. The service is general usable to retrieve information about the booking and its tickets. The returned data contains also information about the refund possibilities and the reasons. A refund reason is necessary to get an offer for a refund.
The booking data can be retrieved via
- ticket id
-
Retrieve booking data by entering the id of the ticket (printed on the ticket).
- or booking id
-
If the booking id is known from the sales process, it can be used to retrieve the booking data.
See version 2 services bookings-controller for details.
5.2. Refund offers
To get an offer for a possible refund, the refund reason must be selected, as the possibilities are returned in the B2P booking-data service. If no possible reason is returned in the booking data service, no refund offer and so no refund will be possible.
B2P refund offers are valid for 20 minutes only. After that the refund offers are discarded. |
Not all products can be refunded and rules apply on partially used products and retention. |
Currently there is only one refund reason possible over B2P. This is set by default.
refundReasonId | description |
---|---|
NICHT_BENUTZT |
Not used. Can only be used before start of validity of the ticket. |
To call the refund offer service it is necessary to hand in all ticket ids, where a refund offer should be created. If one given ticket is not refundable, an error will be returned. If all given tickets are refundable for the same refund reason, one refund offer including refund offer id will be returned. This contains the compelete information of refundable amount, original price, excess, used part and so on.
See refund-offers-controller for details.
5.3. Refund
The refund service confirms the refund of the tickets included in the given refund offer.
It requires the refundOfferIds
as input which are returned in the Refund offers response.
See B2P refund-offers service.
Only if the refund of all tickets of all given refund offers can be successfully refunded, the service will return a success response.
Else an error will be returned and none of the tickets in one of the given refund offers will be refunded.
On success it returns a savBookingId
and a savTicketId
. For the moment this information is not necessary to be stored.
Instead keep the bookingId
and call the B2P booking-data service to check the new status of the tickets.
The refunded amount is always put back on the used payment method. So if the payment has been done with credit card, the refunded amount will be credited to the same credit card. In case of invoice payment, the refunded amount will be credited on the next invoice. |
See the POST service refund-booking-controller for details.
6. Error handling
The B2P web service implements the RFC 7807 (https://tools.ietf.org/html/rfc7807) standard.
6.1. Format
With this besides a HTTP code, a problem json body with further information is returned.
HTTP header
The response header in an error case is always like the following:
content-Type: application/problem+json
The following HTTP codes are used:
HTTP code | Name | Description |
---|---|---|
400 |
Bad Request |
Request contains errors / is malformed. |
401 |
Unauthorized |
Authorization is required. |
403 |
Forbidden |
The requested action is forbidden for the current authorized user. |
404 |
Not Found |
Requested entity could not be found |
406 |
Not Acceptable |
The requested accept header in the request cannot be accepted. |
409 |
Conflict |
Indicates that the request could not be processed because of conflict in the current state of the resource |
For more information please see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
6.2. Example
Here an example for the locations service.
HTTP/1.1 400 Conflict
Content-Type: application/problem+json Content-Language: en
{
"type": "./b2p/locations/name-too-short",
"title": "The given name parameter is too short to do a reasonable locations search.",
"documentation": "https://b2p.app.sbb.ch/docs/index.html#error-handling"
"status": "400"
}
6.3. Services
Only the newest version of each service works with the described error response format.
Common
Certain problem types are thrown by multiple services. In this case, the service name in the reported problem indicates which of the services has reported the problem. These common problems are summarized in the following. The last column indicates which services can report the according problem.
HTTP code | problem-id | title | services |
---|---|---|---|
400 |
request-parameter-invalid |
A request parameter or a combination of them contains invalid values. |
all |
403 |
access-to-booking-id-forbidden |
You are not allowed to access the given booking with the given contract. |
bookings, booking-data |
403 |
product-not-activated |
At least one of the products is not activated on this contract-Id. |
(group-)product-offers, (group-)trip-offers, route-offers, prebooking, booking |
403 |
contract-not-found |
The given contract-Id is invalid. |
(group-)trip-offers, (group-)product-offers, route-offers |
403 |
client-Id-not-linked-to-contract-Id |
Credentials do not match. Check your user-Id and contract-Id. |
(group-)trip-offers, (group-)product-offers, route-offers |
404 |
ticket-not-found |
The ticket with the given id could not be found or does not belong to the given booking id. |
bookings, booking-data |
404 |
origin-and-destination-must-be-different |
The origin and destination UIC must be different. |
trips, trip-offers |
404 |
via-must-be-different-than-origin-and-destination |
The via UIC must be different than the origin and destination UIC. |
trips, trip-offers |
406 |
ticket-format-not-supported |
The requested ticket format is not supported for the given ticket. |
bookings, booking-data |
409 |
illegal-reuse-conversationId |
The conversation-id must not be reused as it is already in a final state. |
trips, trip-offers, prebooking |
Locations
service-name = locations
HTTP code | problem-id | title |
---|---|---|
400 |
name-too-short |
The given name parameter is too short to do a reasonable locations search. |
Trips
service-name = trips
Please also take into account the common problems, as the trips service also reports problems defined there.
HTTP code | problem-id | title |
---|---|---|
404 |
date-too-far-in-the-past |
The date parameter is too far in the past. In general it is possible to search until the last time table switch last December. |
404 |
date-too-far-in-the-future |
The date parameter is too far in the future. In general it is possible to search until the next time table switch in December. In fall a search already to the overnext December is possible. |
404 |
location-uic-invalid |
The origin, destination or via UIC is unknown. |
404 |
trip-id-invalid |
The trip id is invalid. |
400 |
train-type-invalid |
At least one of the given train types is invalid. |
Prices
service-name = prices
HTTP code | problem-id | title |
---|---|---|
404 |
price-not-determinable |
The price cannot be determined. Reasons for this can be e.g. that the passed trip id is invalid, that the trip id is too far in the past or too far in the future, or that the calculation timed out. |
Trip-Offers
service-name = trip-offers
Please also take into account the common problems, as the trip-offers service also reports problems defined there.
HTTP code | problem-id | title |
---|---|---|
404 |
trip-id-too-far-in-the-future |
The trip id parameter or the return trip id parameter is too far in the future. In general it is possible to get an offer for the next 2 months. |
404 |
trip-id-too-far-in-the-past |
The trip id parameter or the return trip id parameter is too far in the past. It is not possible to get offers for this trip. |
404 |
location-uic-invalid |
The origin, destination or via UIC is unknown. |
404 |
trip-id-invalid |
The trip id is invalid. |
Group-Trip-Offers
service-name = group-trip-offers
The Group-Trip-Offers service uses the same problems as the Trip Offers service.
Prebookings
service-name = prebookings
POST Prebookings
HTTP code | problem-id | title |
---|---|---|
404 |
offer-id-not-found |
At least for one offer id the according offer could not be found. The reason for this is that either the offer id expired and is no longer valid or that it never existed and is, thus, invalid. |
400 |
sales-parameter-invalid |
At least one given sales parameter is unknown or contains an invalid value. |
400 |
sales-parameter-required |
At least one required sales parameter was not given in the request. |
400 |
birthdate-does-not-match-age-from-offer |
At least one given passenger has a birthdate that does not match the provided age from the offer |
400 |
saver-fare-quota-exceeded |
The maximum quota of the saver fare level was been exceeded. This information is known earliest on prebooking, so offers will still be returned from service, although not bookable. |
Bookings
service-name = bookings
Please also take into account the common problems, as the bookings service also reports problems defined there.
POST Bookings
HTTP code | problem-id | title |
---|---|---|
404 |
prebooking-not-found |
At least one of the given prebooking ids could not be found. This problem occurs if either the according prebooking id has expired and is no longer valid or if it has not been returned by a previous call of the prebooking service. |
404 |
passenger-ids-of-prebookings-and-offers-not-matching |
There has been at least one passenger id for the prebooking which does not match with a passenger id for the offer. |
404 |
payment-confirmation-missing |
The confirmation that the payment has been successfully done is missing. Please take care that the same x-conversation-id is used in payment process and in bookings. |
Booking data
service-name = booking-data
Please also take into account the common problems, as the booking data service also reports problems defined there.
HTTP code | problem-id | title |
---|---|---|
404 |
booking-not-found |
The booking with the given id could not be found. This problem can occur if the booking with the given id does not exist at all. Besides it can occur if there is a general problem with the processing of the booking. |
403 |
access-to-booking-id-forbidden |
You are not allowed to access the given booking with the given contract. |
404 |
ticket-not-found |
The ticket with the given id could not be found or does not belong to the given booking id. |
406 |
ticket-format-not-supported |
The requested ticket format is not supported for the given ticket. |
Refund-Offers
service-name = refund-offers
HTTP code | problem-id | title |
---|---|---|
404 |
ticket-not-found |
At least for one of the given ids, no ticket could be found. |
404 |
ticket-already-refunded |
At least one ticket has already been refunded. |
404 |
refund-not-possible |
At least one ticket could not be refunded with the given refund reason. At least one ticket is not refundable. The reason could be that the ticket is not refundable or that the given refund reason is not supported. |
Refund Booking
service-name = refunds
POST Refunds
HTTP code | problem-id | title |
---|---|---|
404 |
refund-offer-not-found |
At least one of the given refund offers could not be found. This problem occurs if either at least one of the given refund offers has expired and is no longer valid or if at least one refund offer id has not been returned by a previous call of the refund-offers service. |
7. Status Information
7.1. Service Status
You can check if the B2P service is currently available by calling the status service.
The response contains the overall status of the B2P service as well as the individual statuses of its component.
OK
means that the service/components are operating normally.
ERROR
means that a component is not available or only partially available, or that its functionality is impeded.
The overall status shows ERROR
if at least one component is in status ERROR
.
Note that calls to the B2P API and even whole sales processes may succeed even if the status service shows an error. This is because the B2P API functions you use might not be affected by the partial outage of a component.
The service status response also contains the version of the individual components. This is only informational and not relevant for using the B2P API.
7.2. Service Info
The service info service returns announcements about the service operation.
This is used for example to announce planned maintenances in advance.
7.3. B2P API Status Monitor
The information returned by the status and info services is also available on the B2P API Status Monitor web page.