ČSOB PSD2 API Overview

The ČSOB PSD2 APIs allow you to perform financial operations with the bank clients’ accounts. The supported operations are based on the Payment Services Directive.
Currently the APIs adhere to ČOBS, the recommended implementation standard issued by the Czech Banking Association.

There are three main areas covered by the APIs:

  1. Accounts API

    Operations that allow you to get information about clients’ accounts including their transactions.
    Operations here belong to the PSD2 AISP domain.

  2. Payments API

    The goal of the API area is to perform a payment transaction on the client’s behalf.
    The operations belong to the PSD2 PISP domain.

  3. Balance check for Card-based Payment Instrument Issuer

    This operation allows certified Card-based Payment Instrument Issuers to check availability of a bank client funds without the client being involved in the process.

Additionally, there is a set of registration and authorization services that allow third parties to register their applications and obtain all authorization data needed to use the APIs.

Endpoint URI

The APIs are available under https://api.csob.cz/. The exact location is documented in each service’s details.
For instance the Get accounts service listens at https://api.csob.cz/api/csob/psd2/v1/my/accounts.

Note that the Sandbox and Production URIs are identical.

Transport mechanisms

All APIs are exposed as RESTful services accessible via the HTTP protocol with TLS. JSON format is typically used to transfer data.

Security

Keeping clients’ data and assets safe is key to ČSOB.

In order to call the production APIs, you need to have an official license allowing you to use the PSD2 services.

Mutual TLS authentication

To guarantee high security standards, all communication with the API resources needs to be secured by both the server and also client eIDAS certificates. This makes sure that only licensed parties that can prove their identity and the licensed PSD2 scopes can access the bank client’s accounts and make payment transactions on their behalf.

API keys

Each application that you register will have its own API Key that identifies it. You need to specify the API key value in the APIKEY HTTP header in requests you are sending to most of the API resources.

Authorization

To prove that a bank client gave a consent to access their accounts data or make transactions on their behalf, OAuth 2.0 authorization is used. At this moment we support the Authorization Code Grant.

Requests to most of the resources of the PSD2 APIs need to contain the Authorization HTTP header with a valid OAuth bearer access token proving that the bank client has approved you to make the request.

Paging, sorting, filtering

Data retrieval requests, i.e. REST GET calls, to collections of some resources support paging, sorting and filtering. Please refer to the specific resource documentation to see which of these features are supported.
These optional parameters are passed to requests as query parameters, e.g. GET /transactions?size=25&page=1.

Paging

When requesting a resource that supports paging, you may specify the following request parameters to limit the returned data:

  • page: the number of the requested page to return
  • size: the maximum number of elements per page to be present

By default, when no paging parameters are specified, all elements of the resource collection are expected to be returned.

Sample request:

GET /transactions?size=25&page=1

Sample response:

{
   "pageNumber": 1,
   "pageCount": 12,
   "nextPage": 2,
   "pageSize": 25,
   "totalCount": 298,
   "page": [
      {
         ...item...
      },
      {
         ...item...
      },
      {
         ...item...
      }
   ]
}

Sorting

Selected resources allow you to specify attribute names by which the result collection should be sorted and in which order. You do that by adding the following query parameters:

  • sort: attribute name(s) by which the result should be sorted
  • order: can be asc for ascending order or desc for descending order

Sample request:

GET /accounts?sort=createDate,type,accountNumber&order=desc

Filtering

Some resources allow you to limit the returned entries by a time window. This can be done by using the following query parameters:

  • fromDate: the start date and time for the range to return in the response
  • toDate: the end date and time for the range to return in the response

Sample request:

GET /transactions?fromDate=2016-05-12T05:37:30+02:00&toDate=2016-05-13T10:00:30+02:00

Error handling

The APIs follow REST principles, therefore when an operation succeeds, an HTTP status code from the 2xx family will be returned; in case of error, 4xx for client errors or 5xx for a server error will be returned.

Additionally to the HTTP status code, error responses contain a payload with more information of why the operation has failed.

Error payloads

The data describing why an operation failed has the following application/json type structure:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
   "errors":[
      {
         "error":"COUNTRY_INVALID",
         "parameters":null,
         "message":"Invalid country code."
      },
      {
         "error":"ANOTHER_ERROR_CODE",
         "scope":"account.amount.currency",
         "parameters":null,
         "message":null
      },
      {
         "error":"OTHER_ERROR_CODE",
         "parameters":{
            "AMOUNT_ENTERED":10000,
            "CURRENCY":"EUR",
            "LIMIT":500
         },
         "scope":"orders[3].amount.value",
         "message":"Requested amount is too large"
      }
   ]
}

Here is its JSON schema:

{
   "$schema":"http://json-schema.org/draft-04/schema",
   "type":"object",
   "properties":{
      "errors":{
         "type":"array",
         "description":"Collection of application errors",
         "items":{
            "type":"object",
            "properties":{
               "error":{
                  "description":"Error code",
                  "type":"string"
               },
               "parameters":{
                  "description":"An array of additional elements specific to the given error code. These parameters are always specified in the description of a specific error code.",
                  "type":[
                     "object",
                     "null"
                  ]
               },
               "scope":{
                  "description":"Specifies the JSON path of the request element that caused the error.",
                  "type":[
                     "string",
                     "null"
                  ]
               },
               "message":{
                  "description":"Optional text description. It is not intended for interpretation to the end user, but for example to enrich the error log.",
                  "type":[
                     "string",
                     "null"
                  ]
               }
            },
            "required":[
               "error"
            ],
            "additionalProperties":false
         }
      }
   }
}

OAuth error payloads

For Oauth related errors, we try to follow the conventional format:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
   "error":"invalid_redirect_uri",
   "error_description":"The value of the redirect URI is invalid."
}

It respects the following JSON schema:

{
   "$schema":"http://json-schema.org/draft-04/schema",
   "type":"object",
   "properties":{
      "error":{
         "description":"Error code",
         "type":"string"
      },
      "error_description":{
         "description":"Error description",
         "type":"string"
      }
   },
   "required":[
      "error"
   ],
   "additionalProperties":false
}

Common errors

Below are listed errors that can occur when invoking any of the APIs. API-specific errors are documented in the relevant API documentations.

HTTP status code Error Description
400 invalid_request Bad request
401 unauthorized_client The client is not authorized to make this request
401 access_denied Access denied by the authorization server
403 invalid_scope The value of the scope in the certificate is invalid for the requested resource operation
404 Not Found The requested resource was not found
500 NARR Description of a generic server-side error
500 server_error Internal server error
503 server_error Service is temporarily unavailable
504 server_error Gateway timeout

Getting started

This section walks you through the first steps of using the PSD2 APIs.
It assumes that you already obtained an official license to use the PSD2 services and have an eIDAS certificate.
Bear in mind that even without the certificate, you still can try out the APIs in our Sandbox to get a feel of the services.
When you start using the production environment, all your requests need to be secured with your organization TLS eIDAS certificate.

Register in the Developer Portal

Follow the the registration procedure so that you get your API key.

Register your application details

The next step is to make your first API call to register your application.

You will make a POST call to the https://api.csob.cz/api/csob/psd2/oauth2/register resource.
Send a request similar to

curl -X POST \
  https://api.csob.cz/api/csob/psd2/oauth2/register \
  -H 'APIKEY: l7xxca45406f0e934f7eb5df07d150a38e7b' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
    "application_type": "web",
    "client_name": "FinRadce",
    "client_name#en-US": "FinAdvisor",
    "contact": "[email protected]",
    "logo": "... Base64 encoded image ...",
    "redirect_uris": [
        "https://finadvisor.domain.com/auth-redirect"
    ],
    "scopes": [
        "AISP",
        "PISP"
    ]
}'

The redirect_uris is where the bank will redirect their clients once they are authorized your application to access their data.

You can find details about the request in the API reference.

As a result, you will get something like

HTTP/1.1 200 OK

{
    "api_key": "NOT_PROVIDED",
    "application_type": "web",
    "client_secret_expires_at": 0,
    "client_name": "FinRadce",
    "client_name#en-US": "FinAdvisor",
    "contact": "[email protected]",
    "logo": "... Base64 encoded image ...",
    "client_secret": "fNRF9KUFh3BuiuoIkIzfsy91Zgr8IzJy",
    "redirect_uris": [
        "https://finadvisor.domain.com/auth-redirect"
    ],
    "scopes": [
        "AISP",
        "CISP"
    ],
    "client_id": "TP100141"
}

Notice the three last attributes:

  • client_id: the ID that was assigned to your application; you will make use of it in subsequent calls
  • client_secret: a secret for the client_id you will use to get an access_token and refresh_token
  • client_secret_expires_at: indicates the expiration time in seconds since 1970-01-01T0:0:0Z for the client_secret; 0 means it will never expire

Now your application can start making requests on behalf of the bank clients.

As you might have noticed, the process to obtain the codes and use them to authorize the API calls follows the OAuth 2.0 norm. This is why the application identification is referred to as client_id.

Let the user authorize your application

When making requests to access the bank clients data or make transactions on their behalf, the clients need to authorize such calls.
This is achieved by your application directing the bank client to a ČSOB consent page where the client securely logs in to the bank and authorizes your application to perform the requested operation. The consent page will show the user information about your application you provided in the registration call including the application logo.

GET https://identita.csob.cz/mep/fs/fl/oauth2/auth?state=state123&redirect_uri=https%3A%2F%2Ffinadvisor.domain.com%2Fauth-redirect&client_id=TP100141&response_type=code&scope=AISP

The parameters you pass in the query:

  • client_id: the ID that was issued when you registered your application
  • redirect_uri: the URI (URL-encoded) where the user should be redirected once he or she authorizes your application to act on their behalf; it must be on of the URIs you specified when you registered the application
  • response_type: specify code in order to get the authorization code grant
  • scope: the PSD2 scope(s) the application needs
  • state: an optional arbitrary string that will be returned back to your application so that you can limit security threats

Once your application is successfully granted the permissions by the client, the bank redirects (HTTP 302) the client back to the redirect_uri with an authorization code in the query parameter and if you specified, also with the optional state you can use to verify that the user was redirected back to your application with the authorization code by a real ČSOB server:

https://finadvisor.domain.com/auth-redirect?code=2%2FCOigoxESgm5NIvaYEGG68a5O?state=state123

Get tokens

There is one last thing to do to start using the APIs.
Now that you have the authorization_code, you exchange it for an access_token and refresh_token by issuing a POST request with x-www-form-urlencoded body, e.g.

curl -X POST \
  https://api.csob.cz/api/csob/psd2/oauth2/token \
  -H 'APIKEY: l7xxca45406f0e934f7eb5df07d150a38e7b' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code&code=2%2FCOigoxESgm5NIvaYEGG68a5O&client_id=TP100141&client_secret=fNRF9KUFh3BuiuoIkIzfsy91Zgr8IzJy&redirect_uri=https%3A%2F%2Ffinadvisor.domain.com%2Fauth-redirect'

The response you will get will be similar to

HTTP/1.1 200 OK

{
   "redirectUri": null,
   "refresh_token": "1/jfW4DmmFFKoyybn7XlXXxCQP1oftGoWHLp9nc1Fa1w9Bv9VW5BxEWnqp784C2Uoh",
   "access_token": "3/LSNXm1tXISLOSxJ0C7hsAV8hZiS9Rd5DCTY74XyQmnjxJzyIX3kLhX7lwhKaalGo",
   "token_type": "bearer",
   "expires_in": 3599,
   "scope": "AISP"
}

Start using the APIs!

Now when you have the tokens, you can start calling the APIs.
For instance to list accounts that a bank client has, make the following request:

curl -X GET \
  https://api.csob.cz/api/csob/psd2/v1/my/accounts \
  -H 'APIKEY: l7xxca45406f0e934f7eb5df07d150a38e7b' \
  -H 'Authorization: Bearer 3/LSNXm1tXISLOSxJ0C7hsAV8hZiS9Rd5DCTY74XyQmnjxJzyIX3kLhX7lwhKaalGo' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'

Have a look at the API reference to see what services are available and how to call them.

Moving from Sandbox to Production

By default, all calls you will make ends up in a Sandbox environment and you will get static dummy responses. This is fine to get familiar with the APIs and play around. Once you are ready to hit the real systems and clients accounts, you will want to switch to the production environment. Since you configure the target system via the Developer Portal, the API URIs remain the same.