Skip to content

Profile service endpoints

General headers

Header Name Type Description
Accept-Timezone string Supply a TimeZone id property acquired from Infocenter /timezones route in order to get data with desired time offset

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

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

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 authorization token 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 authorization token 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 allows for example to organize the data for each user /partnerdata/memberdata /partnerdata/preferences

url verb request response description
/partnerdata GET - 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 authorization token 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 - 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.

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

orderDownload sample:

 {
    "orderNumber": "20-100145",
    "orderDate": "2020-02-18T14:33:59.4877486+00:00",
    "partnerAcronym": "christian",
    "@id": "http://localhost:7072/api/orders/20-100145",
    "customer": {
        "email": "kajakchristian@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://tickets.discover.swiss/mailbodies/90043ac2-4d38-4466-bd85-66220a7f4c79_20-100145.html",
    "language": "de",
    "ticket": [
        {
            "name": "ZVV Zürich Card 24 hours",
            "product": {
                  "@id": "https://api.discover.swiss/info/v1/products/NOVA_zurichcard24",
                  "identifier": "NOVA_zurichcard24"
            }
            "additionalType": "e-ticket",
            "ticketNumber": "12761908",
            "ticketTokenId": "541126565860",
            "ticketToken": "https://tickets.discover.swiss/tickets/63e796ad-ac9a-4a71-ac07-17552de7eca2_nr_541126565860.pdf",
            "qrCodeToken": "https://tickets.discover.swiss/qrcodes/d382ddb6-50f0-4025-8527-35635334705a_nr_541126565860.png",
            "dateIssued": "2020-02-18T14:35:29.4205183+00:00",
            "priceCurrency": "CHF",
            "totalPrice": 27.0,
            "underName": {
                "givenName": "Christian",
                "familyName": "Eggenberger",
                "birthDate": "2004-02-18T00:00:00"
            },
            "validFrom": "2020-03-18T05:15:00+00:00",
            "validUntil": "2020-03-19T05:15:00+00:00"
        }
    ],
    "errorTicket": [
        {
            "name": "ZVV Zürich Card 24h",
            "underName": {
                "givenName": "## failure ##",
                "familyName": "Problem",
                "birthDate": "2001-02-18T00:00:00"
            },
            "validFrom": "2020-02-22T05:15:00+00:00",
            "orderItemNumber": "20-100145-2"
        }
    ]
}

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 authorization token must be present as well.

They are always read only for the client.

url verb request response description
/tickets GET scope=
- all
- current
- past
Ticket[] "current" is the default scope and delivers all active tickets.
/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.

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.

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) TermVersionCheck Get term consent state. returns the current version of the term and information if it was accepted/rejected already
/terms POST AcceptTermVersionRequest TermVersionCheck 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.


Last update: September 3, 2020 11:59:36