Skip to main content
Skip table of contents

Access Java SDK usage

Installation

Please first download an Access Java SDK by following the description in Using a generated SDK and choosing “java” as the target language.

A standalone Java project is generated that can be built with either Gradle or Maven. You may either build the project and include the created jar file as a dependency in your application, or directly copy out the generated code into your application.

The code examples in this chapter assume that you used the “Download SDK” button to generate the SDK and chose the V2 API version. By this, the generator runs with default options, using OkHttp as the HTTP client library and GSON as the serialization library.
If you used the finAPI SDK Generator instead to customize SDK generation, you may end up with a different SDK structure and divergent Java code, especially if you change the library parameter. The code examples should still be helpful for you, however, may need to be adapted.

Overview

The src/main/java folder contains the SDK classes. The app subpackage contains API classes to call API service methods. For each section of the Access API (see the left sidebar of the Access API documentation), a distinct API class is available, e.g. the Java class AuthorizationAPI contains all services below the "Authorization" section. The model package contains the API request and response model classes.

The src/test/java folder is not required to run the SDK, but the pre-generated tests are helpful to checkout API usage, as they contain example calls of all API services.

The easiest way to run a service is to just instantiate the API class and execute the desired service method, e.g.:

CODE
new BanksApi().getAndSearchAllBanks(<parameters>);

In this case, the API class uses a pre-configured global configuration. You can change the configuration settings globally by calling the setter methods of Configuration.getDefaultApiClient(). This configuration will by default use https://sandbox.finapi.io as the API base path, so you need your sandbox client credentials to run the following examples.

To find out which parameters you have to provide for a service call, just navigate to the method implementation in your IDE, e.g. to BanksApi.getAndSearchAllBanks. Each method contains an extensive Javadoc comment with the same information as on our API documentation page. The same applies to the model classes.

Usage Examples

The following examples are reduced to the necessary minimum, to help you get easily started with the SDK. However, for a productive application more topics are to be considered, please refer to the Advanced topics section for this.

Authorization and Creation of a User Identity

This section shows how the API calls described in https://documentation.finapi.io/access/authorization-and-creation-of-a-user-identity can be executed via Java SDK.

Get authorized as a client

Instantiate the AuthorizationAPI and provide your client credentials:

CODE
AuthorizationApi authorizationApi = new AuthorizationApi(); 
AccessToken clientToken = authorizationApi.getToken( 
    "client_credentials", 
    "<your client_id",
    "<your client secret>", 
    null,  // request id omitted
    null,  // refreshToken is not required
    null,  // username is not required
    null); // password is not required

Create an Access user

The createUser service requires the client token, so it must be registered before the call.

CODE
Configuration.getDefaultApiClient().setAccessToken(clientToken.getAccessToken());

new UsersApi().createUser(
    new UserCreateParams()
        .id("<username>")
        .password("<password>"),
    null);

Get authorized as a user

Instantiate the AuthorizationAPI and provide your client credentials and the user’s credentials:

CODE
AuthorizationApi authorizationApi = new AuthorizationApi(); 
AccessToken userToken = authorizationApi.getToken(
    "password",   // grant_type to request a user token
    "<your client_id", 
    "<your client secret>", 
    null,         // request id omitted
    null,         // refresh_token is not required 
    "<username>",
    "<password>");

Search for a Bank

The createUser service requires a client or user token to be provided, so it must be registered before the call.
Example: Search for test banks containing “finAPI” for a user

CODE
Configuration.getDefaultApiClient().setAccessToken(userToken.getAccessToken());

PageableBankList bankSearchResult = new BanksApi().getAndSearchAllBanks( 
    null,     // ids omitted 
    "finAPI", // the search string
    null,     // supportedBankingInterfaces omitted
    null,     // location omitted
    null,     // tppAuthenticationGroupIds omitted
    true,     // search for test banks only
    null,     // page omitted
    null,     // perPage omitted
    null,     // order omitted
    null);    // request id omitted
List<Bank> foundBanks = bankSearchResult.getBanks();

Import a new Bank Connection - no Web Form (Licensed customers only)

As a licensed customer, to access banks via the XS2A interface you first have to upload your TPP certificate and TPP credentials for certain banks before you can do a bank connection import. Please refer to Using your own eIDAS Certificates and TPP Credentials for details.

To import a bank connection you must first search for the bank you want to import and determine its id and login credential names for the chosen interface. The following example is hard coded to the finAPI demo bank with the XS2A interface.
For API service calls that connect to a bank, you must provide PSU metadata (see the General user metadata section of our API documentation). The example assumes that you stored the metadata in the variables psuIpAddress, psuDeviceOS, and psuUserAgentbefore.

CODE
Configuration.getDefaultApiClient().setAccessToken(userToken.getAccessToken());

BankConnectionsApi bankConnectionsApi = new BankConnectionsApi();
ImportBankConnectionParams params = new ImportBankConnectionParams()
    .bankId(280001L)
    .bankingInterface(XS2A)
    .addLoginCredentialsItem(new LoginCredential().label("Onlinebanking-ID").value("demo"))
    .addLoginCredentialsItem(new LoginCredential().label("PIN").value("demo"));
try {
    BankConnection bankConnection = bankConnectionsApi.importBankConnection(
        params, 
        psuIpAddress, 
        psuDeviceOS,
        psuUserAgent, 
        null);  // request id omitted
} catch (ApiException apiException) {
    if (apiException.getCode() == 510) {
        ErrorMessage errorMessage = ErrorMessage.fromJson(apiException.getResponseBody());
        ErrorDetails errorDetails = errorMessage.getErrors().get(0);
        ErrorDetailsMultiStepAuthentication multiStepAuthentication = errorDetails.getMultiStepAuthentication();
        String hash = multiStepAuthentication.getHash();
        // handle multistep-authentication dependent on content of 'multiStepAuthentication'
    } else {
      // handle other errors here
    }
}

 As the catch block indicates, an import normally requires a Multi-Step authentication. Use the information in the ErrorDetailsMultiStepAuthentication object to ask your customer for the necessary input and repeat the import call with the enriched data.
Example: Provide a user-given TAN in the challengeResponse field:

CODE
BankConnectionsApi bankConnectionsApi = new BankConnectionsApi();
ImportBankConnectionParams params = new ImportBankConnectionParams()
    .bankId(280001L)
    .bankingInterface(XS2A)
    .addLoginCredentialsItem(new LoginCredential().label("Onlinebanking-ID").value("demo"))
    .addLoginCredentialsItem(new LoginCredential().label("PIN").value("demo"))
    .multiStepAuthentication(new ConnectInterfaceParamsMultiStepAuthentication()
    .hash("<hash returned by initial call")
    .challengeResponse("123456"));
try {
    BankConnection bankConnection = bankConnectionsApi.importBankConnection(
        params, 
        psuIpAddress, 
        psuDeviceOS,
        psuUserAgent, 
        null);  
} catch (ApiException apiException) {
    // handle error
}

Import a new Bank Connection - with Web Form 2.0

The usage of Web Form 2.0 requires additional integration of the Web Form 2.0 SDK into your application. Please refer to Web Form 2.0 Java SDK usage for a detailed explanation and usage examples.

Check the status of the bank connection

After a bank connection import has finished successfully, it’s still in the process of downloading accounts and transactions in the background (please check Post Processing of Bank Account Import/Update for details). So before you can access accounts and transactions, you need to wait until the update status is READY. Use the getBankConnection service for this and provide the id of the imported bank connection:

CODE
BankConnectionsApi bankConnectionsApi = new BankConnectionsApi();
BankConnection updatedbankConnection = bankConnectionsApi.getBankConnection(
        bankConnection.getId(), null);

// TODO check bankConnection.getUpdateStatus() until 'READY'

Get Accounts and Transactions

To query the account data for the imported bank connection, please use the getAndSearchAllAccounts service. The following example queries all accounts:

CODE
AccountList allAccounts = accountsApi.getAndSearchAllAccounts(
    null,  // dont filter accounts ids,
    null,  // no search string provided,
    null,  // don't restrict account types
    null,  // don't filter bank connection ids
    null,  // don't restrict to a min last successful update date,
    null,  // don't restrict to a max last successful update date,
    null,  // don't restrict to a min balance
    null,  // don't restrict to a max balance
    null); // request id omitted

The getAndSearchAllTransactions allows you to query transactions based on many criteria. The following example shows the simplest usage omitting any search criteria, to retrieve all transactions.

CODE
TransactionsApi transactionsApi = new TransactionsApi();
PageableTransactionList transactionsPage = transactionsApi.getAndSearchAllTransactions(
    "userView",
    null, // dont filter transaction ids
    null, // no search string provided
    ... // all further parameters can also be left to null
    1, // fetch the first page
    100, // use a page size of 100
    null, // don't provide order fields
    null);// omit request id
    
// Use transactionsPage.getTransactions() to access the transactions
// Use transactionsPage.getPaging() to check whether further pages are available

Advanced topics

Configure the API basepath

If you instantiate an API class with the default constructor as shown in the examples, the call will be executed against the finAPI sandbox (https://sandbox.finapi.io). This is correct when you start adopting the API, but to switch to our production environment, you need to override the URL to https://live.finapi.io.

The simplest option is to override the URL in the default API client:

CODE
Configuration.getDefaultApiClient().setBasePath("https://live.finapi.io");

Provide a request id

All API service methods except the OAuth2 services declare the String xRequestId parameter. It’s optional and omitted in the examples above, but you should always provide a unique request id which is used for a single request only.

A simple approach could be to use a UUID for this:

CODE
public String requestId() {
    return UUID.randomUUID().toString();
}    

Register the OAuth token

All services except the OAuth services require that you either provide a client or user token along with the call. The simplest approach is to register the token directly with the global default API client that is used by all API classes by default:

CODE
Configuration.getDefaultApiClient().setAccessToken(clientToken.getAccessToken());

or

CODE
Configuration.getDefaultApiClient().setAccessToken(userToken.getAccessToken());

But if you need to serve multiple users in parallel with a server application, this no longer works. A simple option would be to instantiate a new API client and API class for each user call like

CODE
final ApiClient apiClient = new ApiClient();
apiClient.setAccessToken(clientToken.getAccessToken());
BanksApi banksApi = new BanksApi(apiClient);

Another approach could be to still use the default API client, but intercept the token handling on the OkHttpClient level and get the token from a ThreadLocal that is populated in each user's context:

CODE
// Global setup
final ThreadLocal<String> tokenHolder = new ThreadLocal<>();
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(chain ->
    chain.proceed(chain.request().newBuilder()
        .addHeader("Authorization", "Bearer " + tokenHolder.get())
        .build())).build();
Configuration.getDefaultApiClient().setHttpClient(httpClient);

// Per user request in the user thread
tokenHolder.set(clientToken.getAccessToken());
new BanksApi().getAndSearchAllBanks(<parameters>);

Exception Handling

If an API services call returns with an error, an ApiException is thrown that must be handled. As the ApiException contains the raw JSON data only, you should convert it into the structured ErrorMessage object. An exception is for HTTP 401 responses where a different error structure is returned.

CODE
try {
    final Bank bankSearchResponse = new BanksApi().getBank(99999999L,requestId());
} catch (ApiException apiException) {
    if (apiException.getCode() == 401) {
        System.out.println("Not authenticated or invalid access_token");
    } else {
        System.out.println("API call failed with HTTP code " + apiException.getCode());
        final ErrorMessage errorMessage = ErrorMessage.fromJson(apiException.getResponseBody());
        System.out.println("error message is " + errorMessage);
    }
}

Access HTTP information

The Java API service methods used in the examples only return the resource data but give no access to HTTP response information. If you are interested in that, you can use the WithHttpInfo-suffixed variants of the service methods:

CODE
ApiResponse<Bank> bankResponse = new BanksApi().getBankWithHttpInfo(280001L, requestId());
Bank bank = bankResponse.getData();
System.out.println(bankResponse.getStatusCode());
System.out.println(bankResponse.getHeaders().get("X-Request-Id"));
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.