Page tree

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 40 Next »

Release Information

1.3.3

Target audienceThis documentation is intended for developers and system integrators which enable customer systems for interaction with the ZSR Webservice.
Summary

The ZSR Webservice is the public API to connect customer specific solutions to the SASIS care provider register in a well structured an secured manner. 

The reader of this documentation will find the API description in detail as well as further information about the access and authorization mechanisms.

Content

Introduction

The ZSR Webservice provides a possibility to connect enterprise systems to SASIS internal data structures to maintain and interrogate care providers and their clearing numbers. 

The ZSR Webservice is designed to replace existing file based data exchange with a high performance and secure online interface. The API itself is REST based and supports tenant specific requests which is handled based on the authentication of the API client.

The main functionality is:

  • Interrogation of clearing number (ZSR/RCC/CPR number) or employee number (K-Nummer/Numéro C/Numero di controllo) overviews and details.
  • Interrogation of comments on health services.
  • Interrogation of filtered clearing numbers and/or employee numbers based on subscription search options.
  • Maintenance of care provider certification periods (mainly used by health service certifiers).



ZSR Webservice Specification

Open API Specification



Status codes

The SASIS Regis uses standard http status codes.

The following status codes will generally be used by the API: 

Status CodeDescription
200Success
202Accepted; Request is valid and business process could be triggered successfully.
400Bad Request; The request data is invalid.
401Unauthorized; The caller does not have sufficient privileges to perform the call.
403Forbidden;  The server is refusing the action.
500Internal Server Error; Any unexpected internal failure.

Referenced Algorithms

Clearing number check digit

The clearing number has the following structure:

  • A leading char as check digit
  • A four digit sequential number
  • A two digit number circle / canton number

The leading char of the clearing number is created and validated as follows:

  • Each number is multiplied with its position (calculate from the right end).
  • All products are summarized into one sum.
  • Modulo 26 of the sum denotes the char in the alphabet (result 0 results in char 'Z'). 

Example L248519:
(9*1)+(1*2)+(5*3)+(8*4)+(4*5)+(2*6) = 90
90 mod 26 = 12
12th char in the alphabet = L

UID ECH0097 check digit

The ECH0097 enterprise identification number (Unternehmensidentifikationsnummer UID, Numéro d’identification des entreprises IDE, Numero d’identificazione delle imprese IDI) has the following structure:

  • ISO-Alpha-3 Code (ISO 3166-1) of Switzerland (CHE)
  • 8 digit pseudo random number
  • check digit

The check digit is created and validated as follows:

  • Each digit of the pseudo-random number is multiplied with a predefined multiplier: 54327654
  • All products are summarized into one sum.
  • 11 minus Modulo 11 of the sum defines the check digit.

Example CHE-114.617.288:
(1*5)+(1*4)+(4*3)+(6*2)+(1*7)+(7*6)+(2*5)+(8*4) = 124
124 mod 11 = 3
11 - 3 = 8


Authentication / Autorisation

The authentication is based on OpenID Connect, an identity layer on top of OAuth 2.0 and its corresponding flows/grants. For application integration, the resource owner password flow using the OAuth 2.0 password grant is to be used. 

The SASIS IAM infrastructure acts a OpenID provider / authorization server.

  1. The API Client requests the token endpoint from the auth server.
  2. The token endpoint is returned to the API Client.
  3. Request an access token from the auth server by providing the following post request parameters:
    1. grant_type: set to 'password'
    2. client_id: provided individually by SASIS
    3. client_secret: provided individually by SASIS
    4. username: provided individually by SASIS
    5. password: provided individually by SASIS
    6. scope: set constantly to 'openid profile email offline_access roles c1s_profile cpr'
  4. The access token as well as the refresh token is returned to the API Client.
  5. The specific API resource is called providing the access token in as bearer in the Authorization http header:
    'Authorization: Bearer <access token>'
  6. The API responds to the request.
  7. Once the access token expired, the previously received refresh token is used to request a new access token from the auth server by providing the following parameters:
    1. grant_type: set to 'refresh_token'
    2. client_id: provided individually by SASIS
    3. client_secret: provided individually by SASIS
    4. scope: set constantly to 'openid profile email offline_access roles c1s_profile cpr'
    5. refresh_token: The refresh token received with the last access token.
  8. A new access token as well as a new refresh token is returned to the API Client.
  9. The specific API resource is called providing the new access token in as bearer in the Authorization http header:
    'Authorization: Bearer <access token>'
  10. The API responds to the request.

Access token

The access token response contains additional information:

Access token response
{
  "access_token": "MTQ0NjOkZmQ5OTM5NDE9ZTZjNGZmZjI3",
  "refresh_token": "GEbRxBNZmQOTM0NjOkZ5NDE9ZedjnXbL",
  "token_type": "bearer",
  "expires_in": 300,
  "scope": "openid profile email offline_access roles c1s_profile cpr"
}

The token itself is a JWT and can therefore be decoded on the JWT website.

The expires_in field defines the validity period of the token in seconds. Afterwards, a new token must be retrieved.

Code samples

A complete c# sample shows how to access one specific API resource (numbers): 

Authentication in other languages follows the same procedure.

The following code snippets explain the procedure on a step-by-step basis:

1./2. Retrieve the auth servers token endpoint
        /// <summary>
        /// Loads the IAM configuration.
        /// </summary>
        private async Task<DiscoveryResponse> GetDiscoveryDocumentAsync(CancellationToken ct)
        {
            using (var client = new HttpClient())
            {
                var discoveryResponse = await client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
                {
                    Address = "[AuthorityUrl]"
                }, ct).ConfigureAwait(false);

                if (discoveryResponse.IsError)
                    throw new Exception(discoveryResponse.Error);

                return discoveryResponse;
            }
        }

3./4. Request access and refresh token
        /// <summary>
        /// Gets a new token response with a username and password.
        /// </summary>
        private async Task<TokenResponse> RequestTokenAsync(CancellationToken ct)
        {
            using (var client = new HttpClient())
            {
                var discoveryResponse = await GetDiscoveryDocumentAsync(ct).ConfigureAwait(false);

                var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
                {
                    ClientId = "[ClientId]",
                    ClientSecret = "[ClientSecret]",
                    UserName = "[UserName]",
                    Password = "[Password]",
                    Address = discoveryResponse.TokenEndpoint,
                    GrantType = OidcConstants.GrantTypes.Password,
                    Scope = string.Join(" ", _scopes),
                }, ct).ConfigureAwait(false);

                if (tokenResponse.IsError)
                    throw new Exception(tokenResponse.Error);

                return tokenResponse;
            }
        }

7./8. Token refresh strategy based validity of cached token response and request new access token
        /// <summary>
        /// Gets the access token by either requesting a new token or by using the refresh token of an already existing token.
        /// </summary>
        private async Task<string> GetAccessTokenAsync(CancellationToken ct)
        {
            if (_tokenResponse == null)
            {
                // Creates a new token response
                _tokenResponse = await RequestTokenAsync(ct).ConfigureAwait(false);
            }
            else
            {
                var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();

                // Parses JWT access token
                var jwtSecurityToken = jwtSecurityTokenHandler.ReadToken(_tokenResponse.AccessToken) as JwtSecurityToken;

                // The access token might be valid now, but expired the very next millisecond.
                // Thus, add a reasonable reserve in minutes for the validity time comparison below.
                var comparisionCorrectionInMinutes = 1;

                // Compares the access token life time with the current time, modified by the comparison correction value.
                if (jwtSecurityToken.ValidTo < DateTime.UtcNow.AddMinutes(comparisionCorrectionInMinutes))
                {
                    // Updates the existing token response
                    _tokenResponse = await RefreshTokenAsync(_tokenResponse.RefreshToken, ct).ConfigureAwait(false);
                }
            }

            return _tokenResponse.AccessToken;
        }

        /// <summary>
        /// Gets an updated token response by using a refresh token.
        /// </summary>
        private async Task<TokenResponse> RefreshTokenAsync(string refreshToken, CancellationToken ct)
        {
            using (var client = new HttpClient())
            {
                var discoveryResponse = await GetDiscoveryDocumentAsync(ct).ConfigureAwait(false);

                var tokenResponse = await client.RequestTokenAsync(new TokenRequest
                {
                    ClientId = "[ClientId]",
                    ClientSecret = "[ClientSecret]",
                    Address = discoveryResponse.TokenEndpoint,
                    ClientCredentialStyle = ClientCredentialStyle.AuthorizationHeader,
                    GrantType = OidcConstants.GrantTypes.RefreshToken,
                    Parameters =
                    {
                        { "refresh_token", refreshToken },
                        { "scope", string.Join(" ", _scopes) }
                    }
                });

                if (tokenResponse.IsError)
                    throw new Exception(tokenResponse.Error);

                return tokenResponse;
            }
        }


5./6./9./10. API resource call using the access token in the Authorization http header
        /// <summary>
        /// A simple CPR API number search request.
        /// </summary>
        private async Task<BulkResponse> CprApiSampleRequestAsync(string accessToken, CancellationToken ct)
        {
            BulkResponse bulkResponse = new BulkResponse();

            using (var client = new HttpClient())
            {
                client.SetBearerToken(accessToken);

                var response = await client.GetAsync($"https://[CprBaseUrl]/ApiGateway/api/v1/numbers?searchOptions=Okp&offset=0&limit=10", ct).ConfigureAwait(false);

                if (!response.IsSuccessStatusCode)
                    throw new Exception("There was a problem with the request");

                string content = await response.Content.ReadAsStringAsync();

                if (content != null && content.Length > 0)
                {
                    bulkResponse = JsonConvert.DeserializeObject<BulkResponse>(content);
                }
            }

            return bulkResponse;
        }

Plain API Call (putting everything together)
        var accessToken = await GetAccessTokenAsync(ct).ConfigureAwait(false);

        var cprApiResponse = await CprApiSampleRequestAsync(accessToken, ct).ConfigureAwait(false);

Connection Settings

SettingTest EnvironmentLive Environment
AuthorityUrlhttps://openid-test.santesuisse.chhttps://openid.santesuisse.ch
CprBaseUrlhttps://stagecurrent.zsrnext.ch/https://www.zsrnext.ch
ClientId1)1)
ClientSecret1)1)
UserName1)1)
Password1)1)

1) To be provided individually by SASIS. Please contact: support@sasis.ch

  • No labels