Skip to content

Profile service endpoints

General headers

Header Name Type Description
Ocp-Apim-Subscription-Key string Appropriate subscription key you can get in the developer portal
Accept-Timezone string Supply a TimeZone id property acquired from Infocenter /timezones route or IANA code in order to get data with desired time offset. The default is UTC.
Content-Type string default: application/json;charset=UTF-8
Use a different charset if your application is not sending the data in utf-8. for example: application/json;charset=ISO-8859-1

General query params

This query params might be applied to the next endpoints: * GET /orders * GET /partnerdata * GET /tickets

Param Name Type Description
continuationToken string Continuation token used to get next page of data read about paging
top int Number of next set of entities read about paging
includeCount bool if true - includes total count of entities

Token and helpers

creates tokens and main profile objects

url verb request parameters response
/token POST grant_type
max_refresh_lifetime
refresh_token
ProfileToken Response
If susccessful this endpoint always retuns a new token to access the resulting profile.
{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQcm9maWxlSWQiOiIyZDk5ZThlOS03ODJhLTQ4ZWEtODRiNi0zYzdhYTRkMjEyYzQiLCJJc0d1ZXN0IjoiVHJ1ZSIsIm5iZiI6MTU5MjIxNzEwNiwiZXhwIjoxNTkyMjIwNzA2LCJpYXQiOjE1OTIyMTcxMDZ9.4qFf7YYkovASjeiqgtFQTMa-HqmAf_Snnu97sVx3l3Y",
    "tokenType": "Bearer",
    "expiresIn": 1592220706,
    "expiresInDate": "2020-06-15T11:31:46+00:00",
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJSZWZyZXNoSWQiOiIyZDk5ZThlOS03ODJhLTQ4ZWEtODRiNi0zYzdhYTRkMjEyYzQiLCJuYmYiOjE1OTIyMTcxMDYsImV4cCI6MTU5MjMwMzUwNiwiaWF0IjoxNTkyMjE3MTA2fQ.z16y-IlVsIgkhMwk1BkOo_5FupBJT8axIPIhBX3NuE8"
}

Info

There can be several different valid tokens for the same profile with different expiration date.

Request parameters

Name value
grant_type see below
max_refresh_lifetime wished refresh token lifetime in days.
refresh_token the refresh token which was delivered within a past token reference

grant_type

grant_type description remarks
guest creates a new guest- Person object in the profile. If there is a profile-ID present in the request header it will return a BadRequest-Error
authorization_header returns a new profile token to an existing profile based on the Authorization header
or creates a new Person object in the profile, copies azure B2C data into it and returns a token for the profile.
authorization_header
+ valid ProfileToken-header
Adds the Azure B2C data to the existing profile. If there is already a profile with the provided B2C ID, the 2 profiles are merged as described below (the old B2C profile survives)
refresh_token returns a new token response if the refresh token is valid

max_refresh_lifetime

wished refresh token lifetime in days. This value should be set as low as possible. There is an upper limit set by discover.swiss: 450 days

Tip

Not in all scenarios the same lifetime of the refresh token makes sense. For client apps a longer lifetime is better so the user is still logged in even after several month of not using the App. But on web application this is a more serious security issue and the refresh token should only be valid for the duration of an expected user "session".

refresh_token

The refreshToken from one of tha past token request-responses.

Warning

If you are using guest profiles without authentication: Once the refresh token has expired you can not get a new one nor a new profile token.

Merge profiles A → B

If your application offers profile functionality "as a guest" without B2C authentication and then offers the guest to add/use a login for his account you must call the token endpoint in this manner

POST {profileServiceUrl}/token?grant_type=authorization_header
ProfileToken: yyy.yyyy.yyyy
Authorization: Bearer xxx.xxx.xxx
where the profile token represents the current profile as a guest and the Authorization the login. The server then decides if there is a merge of profiles necessary or not: Scenario

  1. A user is acting «as a guest» and therefore with a specific profile, let's call it A profileToken-header -> profile A
  2. Then the user creates a B2C Account and A is extendend by the B2C id Authorization-header -> is not pointing to a profile yet -> no merge is necesssary

  3. A user is acting «as a guest» and therefore with a specific profile, let's call it B profileToken-header -> profile B

  4. Then he logs in with an existing B2C account and now there would be 2 profiles A and B which would be connected with the same login Authorization-header -> profile A -> a merge of A and B is necssary (and performed automaticallay)

A gets merged into B → B survives

  • orders and tickets: move all from A to B (all objects from A get the profileID of B)
  • parties: move all from A to B (all objects from A get the profileID of B)
  • PartnerData: move all from A to B (all objects from A get the profileID of B) But if there is partnerdata existing with the same name-property the object of B survives and the one from A gets deleted
  • delete person A

Person / me

url verb request response description
/me GET - Person returns the person-data of the current profile
update me /me PATCH Person or
some properties of it
Person
/me/profileimage GET - string / base64 Downloads the thumbnail of the media as a base64 encoded string (same like /media/{identifier}/thumbnail)
/me/verify/email PUT - - resend the account verification email. Email will only be sent if IdentificationLevel is EmailNotVerified

Note

When you create a profile it is empty, information should be updated by using PATCH request {profileUrl}/me

Info

There is no POST nor PUT to replace or create the compete object. The logic always gets the existing object and applies changes to it.

Party / group of fellow travelers

Data is selected based on the profile token. If the profile is linked to a B2C account a valid, suitable authorizationtoken must be present as well.

url verb request response description
/parties GET - Party[] Gets all parties (groups) of the current user
/parties/{identifier} GET identifier Party Gets one single party (group)
/parties POST Party Party Creates party or returns BadRequest and validation messages
/parties/{identifier} PUT Party Party Updates party or returns BadRequest and validation messages
/parties/{identifier} DELETE - - remove party from data base

Partner data / destination specific profile

Data is selected based on the profile token and the subscription key. If the profile is linked to a B2C account a valid, suitable authorizationtoken must be present as well.

Partner data is linked to the partner's acronym. Access is checked by subscription key

Instead of an ID which is different for every profile a name (made of letters and numbers) is used to store different named-profiledata for each user. This allowsfor example to organize the data for each user /partnerdata/memberdata /partnerdata/preferences

url verb request response description
/partnerdata GET - PartnersDataResponse<PartnerData> gets all groups of the current user
/partnerdata/{name} GET name PartnerData gets one single group
/partnerdata POST PartnerData PartnerData or returns BadRequest and validation messages
/partnerdata/{name} PUT PartnerData PartnerData or returns BadRequest and validation messages
/partnerdata/{name} DELETE - -

Order

Data is selected based on the profile token and the subscription key. If the profile is linked to a B2C account a valid, suitable authorizationtoken must be present as well.

Orders are always read only for the client.

url verb request response description
Get all orders of a profile /orders GET OrdersResponse<Order>
Get a single order /orders/{orderNumber} GET orderNumber Order

Orderinfo download

Data is selected only by the orderToken which is passed to the e-mail flow. There is no authentication on this endpoint. This endpoint is alternate way to get full information about tickets instead of requesting all tickets by id. Endpoint can be used to get order with full ticket list including child tickets.

url verb request response description
/orderinfos/{orderToken} GET orderToken OrderDownload

orderDownload sample:

{
    "orderNumber": "20-107699",
    "orderDate": "2020-12-10T20:13:51.9800292+00:00",
    "partnerAcronym": "discover.swiss",
    "@id": "https://api.discover.swiss/test/profile/orders/20-107699",
    "customer": {
        "email": "ordetest@gmail.com",
        "familyName": "Eggenberger",
        "givenName": "Christian",
        "gender": "Male",
        "birthDate": "1967-12-07T00:00:00"
    },
    "orderStatus": "Fulfilled",
    "priceCurrency": "CHF",
    "totalAmount": 27.0,
    "totalAmountCHF": 27.0,
    "mailBodyToken": "https://discoverswistestbusiness.blob.core.windows.net/mailbodies/07dcc9fc-403b-42ca-8b59-6d15e5aa8844_20-107699.html",
    "language": "de",
    "ticket": [
        {
            "name": "SBB - ZVV Zürich Card 24 Stunden",
            "product": {
                "@id": "https://api.discover.swiss/test/info/products/SBB_zurichcard24",
                "identifier": "SBB_zurichcard24"
            },
            "additionalType": "e-ticket",
            "ticketNumber": "640374080",
            "ticketTokenId": "256754788543",
            "bookingNumber": "640374080",
            "ticketToken": "https://discoverswistestbusiness.blob.core.windows.net/tickets/7c36341a-855a-4119-95b7-4b3ecff8eaa6_nr_256754788543.pdf",
            "qrCodeToken": "https://discoverswistestbusiness.blob.core.windows.net/qrcodes/f26dd17b-ca36-454e-b65a-62adbaa9a743_nr_256754788543.png",
            "htmlToken": "https://discoverswistestbusiness.blob.core.windows.net/htmls/f41ed5b1-034e-4db2-97c7-18fef39356e3_nr_256754788543.html",
            "dateIssued": "2020-12-10T20:14:32.4031913+00:00",
            "priceCurrency": "CHF",
            "totalPrice": 27.0,
            "underName": {
                "givenName": "SBB",
                "familyName": "Tester",
                "birthDate": "1967-12-07T00:00:00"
            },
            "validFrom": "2020-12-29T09:00:00+00:00",
            "validUntil": "2020-12-29T09:00:00+00:00"
        }
    ]
}

Tickets

Data is selected based on the profile token and the subscription key. If the profile is linked to a B2C account a valid, suitable authorizationtoken must be present as well.

They are always read only for the client.

url verb request response description
/tickets GET scope=
- all
- currentAndFuture
- current
- past

orderNumber(optional)
TicketsResponse<Ticket> "currentAndFuture" is the default scope and delivers all tickets which are now active and in the future.
The list is ordered by ValidFrom asc in scope current and currentAndFuture, ordered by validUntil desc in all other cases.
/tickets/{identifier} GET identifier Ticket
/tickets/{identifier}/download GET identifier Binary[] / File response downloads the ticket as a file in the correct content type (PDF, jpg, ...)
public transportation: QR code only - not full PDF
/tickets/{identifier}/base64 GET identifier string / base64 Gets the content of the ticket as base64 encoded string. which is sometimes helpful to display in a client application.
tickets/guestcard PUT id, provider=
- ds
- 4tix
Ticket Copy created by provider guestcard or ticket to profile

Info

public transportation: the download contains the QR code only - not the full PDF. The full PDF is accessible through the url in the ticketToken property of the ticket object.

GuestCardRequest sample:

{
    "id": "107699",
    "provider": "4tix"
}
Guest card can be provided by 4tix or via discover.swiss b2b marketplace. According to that id should be either 4tix guest card id or ticket id.

Business trail

url verb request response description
/businesstrail POST BusinessTrail empty Creates a new Business-trail entry
or returns BadRequest and validation messages

Terms

url verb request response description
/terms/{termCode} GET the code of the Term (s and conditions) TermVersion Get term consent state. returns the current version of the term and information if it was accepted/rejected already
/terms POST AcceptTermVersionRequest TermVersion Accept/reject a termversion.
Adds the term version to the Business Trail or returns BadRequest and validation messages.
/anonymous/terms POST query-string: max_refresh_lifetime={ n }
body: AcceptTermVersionRequest
NO ACCESS TOKENS NEEDED
ProfileToken Response Accept/reject a termversion and create a guest account. This request combines the creation of a guest profile and a BusinessTrail entry and is intended to use to store cookie consents/dissent of a website without any kind of profile and authentication messages.

Info

If the posts are executed several times there will be several entries, but that doesn't hurt. The existence of the terms get's checked.

Media

url verb request response description
/media GET ProfileMedia[] Gets all media of the current user
/media/{identifier} GET identifier ProfileMedia Gets one single media
/media/{identifier}/download GET identifier Binary[] / File response Downloads the media as a file in the correct content type (png, jpg, ...)
/media/{identifier}/base64 GET identifier string / base64 Downloads the media as a base64 encoded string
/media/{identifier}/thumbnail GET identifier string / base64 Downloads the thumbnail as a base64 encoded string
/media POST, PUT Parameters: additionalType
encodingFormat
Body: byte[]
ProfileMedia POST and PUT are supported and currently only 1 additional type and 1 media object per type is supported there is a upload size limit 5Mb

OpenAPI document

All methods and response models can be viewed in the Developer Portal. To generate an API client you can use the following URLs without user authentication but still with the Subscription Key in the Header (Ocp-Apim-Subscription-Key) or as Query Parameter (subscription-key=<your-surbscription-key>):


Last update: February 1, 2024 17:37:15