NAV Navbar

wallis.Multibank

wallis.Multibank provides a turnkey multi-banking API that connects fintechs with banks in order to retrieve their customers' financial data. Using our multi-banking API, you can access the basic financial data of customers of almost all german banks via public interfaces.

Feature Overview

image image

wallis.Multibank offers traditional banking functionality alongside various transaction refinements.

You can use wallis.Multibank to:

Quick Start Basics

This Cookbook enables you to get started quickly with wallis.Multibank. Before you begin, please register for an wallis.Multibank Sandbox Manager account.

Once you are registered, we recommend using our API Explorer to familiarize yourself with the API. The API Explorer contains the complete endpoint documentation. It allows you to test all wallis.Multibank endpoints and assists you with OAuth 2.0 authorization.

For general information about wallis.Multibank please refer to overview page.

Overview

Here are the steps necessary to proceed from registering a user to acquiring all of that user's transactions:

  1. Register with the Sandbox Manager
  2. Get a registration token
  3. Register the user
  4. Get a banking token
  5. List all providers
  6. Get access data for selected providers
  7. Create an access for the user
  8. Get all accounts
  9. Get all transactions for the account

wallis.Multibank OAuth Flow

oauth token flow as sequence diagram
The wallis.Multibank OAuth flow (step 2 to 4) as sequence diagram.

STEP 1: Register with the Sandbox Manager

The first step you need to complete before you can use wallis.Multibank is to register with the Sandbox Manager. With every registration we create a bank access with accounts, portfolios and transactions for our testing bank, the Sandbank. You can use the this bank access for your own testing purposes. All of the credentials you need can be found in the Sandbox Manager. You can also enter your own test data.

STEP 2: Get a registration token

The registration token is used to register an actual user with wallis.Multibank. To obtain a registration token, the external application authenticates with the application credentials. Further endpoints are inaccessible with this token.

You need to add a basic authorization header with your clientId and clientSecret to your request to obtain the registration token. You’ll find the credentials in the Sandbox Manager. These values must be encoded with base64 in a single string.

Example: Encode basic auth credentials in Java

String credentials = String.format("%s:%s", <clientId>, <clientSecret>);
String AUTH_BASIC_BASE64 = Base64.getEncoder()
                                 .encodeToString(credentials.getBytes( StandardCharsets.UTF_8 ));

Request

POST /auth/v1/oauth/token?grant_type=client_credentials HTTP/1.1
Authorization: Basic <AUTH_BASIC_BASE64>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "access_token": "<REGISTRATION_TOKEN>",
    "token_type": "bearer",
    "expires_in": 1199,
    "scope": "ANON ENC_DIS",
    "jti": "8423faa7-e2ea-47c1-82a7-ace341506da8"
}

The "expires_in" value in the response contains the number of seconds until expiration. This token will expire in about 20 minutes.

STEP 3: User registration

Please insert the <REGISTRATION_TOKEN> fetched in the previous step for the "bearer" token as the "Authorization" header in a request to the "user registration" endpoint.

Request

POST /ahoi/api/v2/registration HTTP/1.1
Authorization: Bearer <REGISTRATION_TOKEN>

Response

HTTP/1.1 201 CREATED
Content-Type: application/json; charset=utf-8

{
  "installation": "<INSTALLATION_ID>"
}

Registration with user information

If your licence model requires every user to be identified, you must use the "personal user registration" endpoint and supply at least an email address. Optionally you can add a name and mark the user as "politically exposed person".

Request with user information

POST /ahoi/api/v2/registration/personal HTTP/1.1
Authorization: Bearer <REGISTRATION_TOKEN>

{
    "email": "some@e.mail"
    "name": "John Doe"
    "politicallyExposedPerson": false
}

STEP 4: Get a banking token

With the <INSTALLATION_ID> you can now get a banking token. This token authenticates the actual user with wallis.Multibank and can be used by your application to execute banking actions on behalf of the user. With this token, all endpoints can be used except registration, for which you need a registration token.

You need to send a X-Authorization-Ahoi header with this request. The header value is an encoded JSON string that consists of the <INSTALLATION_ID>, a random string with a minimum length of 32 characters as nonce and the current date in ISO 8601 format.

{
    "installationId":"<INSTALLATION_ID>",
    "nonce":"45b04437-33ca-49af-82cf-6ddd5d920a1d",
    "timestamp":"2022-06-24T09:35:58.803624Z"
}

Encode this data with Base64URL to create the required header.

Example: Create X-Authorization-Ahoi header in Java

String installationId = "<INSTALLATION_ID>";
// create nonce
String nonce = UUID.randomUUID().toString();
// create timestamp
String timeStr = Instant.now().toString();
// create json string
String xAuthAhoiJson = String.format("{\"installationId\":\"%s\",\"nonce\":\"%s\",\"timestamp\":\"%s\"}",
                                        installationId, nonce, timeStr);
// encode encrypted header value
String XAUTH_AHOI_BASE64_URL_ENC = Base64.getUrlEncoder().withoutPadding()
                                         .encodeToString(xAuthAhoiJson.getBytes( StandardCharsets.UTF_8 ));

Request

POST /auth/v1/oauth/token?grant_type=client_credentials HTTP/1.1
Authorization: Basic <AUTH_BASIC_BASE64>
X-Authorization-Ahoi: <XAUTH_AHOI_BASE64_URL_ENC>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "access_token": "<BANKING_TOKEN>",
    "token_type": "bearer",
    "expires_in": 3599,
    "scope": "ACCESS_C ACCESS_R ACCESS_U … TRANSFER_C ENC_DIS",
    "CONTEXT_ID": "Jz5Hq14Uc6Y3vo…VuuF3u9OLqpkHXXG9yXPDWIbgevo8yNe",
    "jti": "3ee3c5aa-77f0-44cb-aec1-69c8665a4bec"
}

Once again, the expires_in value in the response contains the number of seconds until expiration. This token will expire in about 60 minutes.

From now on, you have to include this banking token ("access_token") in each of your requests for this user.

STEP 5: List all providers

To set up the bank accounts, a banking access needs to be created first. For this the "id" of the provider (i.e., bank) is required.

You can obtain a list of all available providers via the "list bank providers" endpoint.

Request

GET /ahoi/api/v2/providers HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
  {
    "type": "BankProvider",
    "id": "<PROVIDER_ID>",
    "name": "Sandbank",
    "location": "Hamburg",
    "accessDescription": null,
    "supported": true,
    "bankCode": "99994000",
    "bic": "TESTBICXXXX"
  }
]

STEP 6: Get provider access data

Next you will need the fieldDescriptions of the provider, which describe the required fields to authenticate with the bank. Later these should be used to create a user interface to enter the access credentials. For the time being we will use them to send the required values when creating the access.

These fieldDescriptions are available at each provider resource which can be accessed via the "get provider" endpoint.

Request

GET /ahoi/api/v2/providers/<PROVIDER_ID> HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "type": "BankProvider",
    "id": "<PROVIDER_ID>",
    "name": "Sandbank",
    "location": "Hamburg",
    "accessDescription": {
        "infoText": "Sofern Ihr Institut Ihnen keine separate Benutzerkennung mitgeteilt hat, geben Sie bitte unter Benutzerkennung Ihre Kontonummer ein. In Abhängigkeit von Ihrem Kreditinstitut können zusätzliche Informationen, wie beispielsweise eine Kundennummer, hinterlegt werden. Diese Eingabe ist meistens optional.",
        "fieldDescriptions": [
            {
                "id": "USERNAME",
                "label": "Benutzerkennung",
                "masked": false,
                "format": "DEFINITELYALPHANUMERIC",
                "transferredEncrypted": false,
                "lengthMin": 1,
                "lengthMax": 30
            },
            {
                "id": "PIN",
                "label": "PIN",
                "masked": true,
                "transferredEncrypted": false,
                "format": "UNSPECIFIED",
                "lengthMin": 5,
                "lengthMax": 5
            }
        ]
    },
    "supported": true,
    "bankCode": "99994000",
    "bic": "TESTBICXXXX"
}

STEP 7: Create an access

Now you have all the information you need to create a banking access. From the previous step you know that you need a USERNAME and a PIN for the Sandbank. Please refer to Sandbox Manager for the requested values.

Accesses are created via the "get a new access" endpoint.

Create Access Request

POST /ahoi/api/v2/accesses/async HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>
Content-Type: application/json

{
    "providerId": "<PROVIDER_ID>",
    "type": "BankAccess",
    "accessFields": {
        "USERNAME": "myuser", 
        "PIN": "12345"
    }
}

Create Access Response

HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8

{
    "type": "AccountSetupTask", 
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "CREATED",
    "cause": "NONE",
    "accessId": null,
    "bankMessages": []
}

You receive the task with which wallis.Multibank is creating an Access and storing all supported Accounts from the bank. The task is working in the background and will make information available via the task resource.

You can poll its status via the "fetch state of task" endpoint or by simply registering a webhook to receive notifications.

Task request

GET /ahoi/api/v2/tasks/<TASK_ID> HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Task Response (in progress)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "type": "AccountSetupTask", 
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "IN_PROGRESS",
    "cause": "NONE",
    "accessId": null,
    "bankMessages": []
}

When you receive this state please poll again until the state is either SUCCESS or FAILURE.

Task Response (success)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "type": "AccountSetupTask", 
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "SUCCESS",
    "cause": "NONE",
    "accessId": "<ACCESS_ID>",
    "bankMessages": []
}

Response (error)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "type": "AccountSetupTask",
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "FAILURE",
    "cause": "AUTHORIZATION_WRONG",
    "accessId": null,
    "bankMessages": [
        {
            "level": "ERROR",
            "message": "Fehlerhafte Authorisierung!",
            "errorCode": "UNCLASSIFIED"
        }
    ]
}

STEP 8: Get all accounts

With the access you have created, you can now acquire the related accounts by using the <ACCESS_ID> as returned by the successful task at the "list accounts" endpoint.

Request

GET /ahoi/api/v2/accesses/<ACCESS_ID>/accounts HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
    {
        "type": "BankAccount",
        "id": "<ACCOUNT_ID>",
        "name": "Giro Classic",
        "..."
    },
    {
        "type": "BankAccount",
        "id": "f0629fd2-0f95-4f67-953d-e62bda0fa77d",
        "name": "Giro Classic",
        "..."
    },
    {
        "type": "BankAccount",
        "id": "4267646a-656e-44d7-a06b-854d4e53dc9e",
        "name": "Depot",
        "..."
    }

STEP 9: Get all transactions

For each account you can now list all transactions by using the <ACCESS_ID> and the <ACCOUNT_ID> at the "list transactions for account" endpoint.

Request

GET /ahoi/api/v2/accesses/<ACCESS_ID>/accounts/<ACCOUNT_ID>/transactions HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
    {
        "type": "GiroTransaction",
        "id": "17b1f6bd-034d-4e17-a3df-e7f02e52ca3e",
        "amount": {
            "value": -6522,
            "currency": "EUR"
        },
        "bookingDate": "2018-10-13T12:00:00Z",
        "valueDate": "2018-10-13T12:00:00Z",
        "creditor": "Stadtreinigung Musterstadt",
        
    },
    {
        "type": "GiroTransaction",
        "id": "e3a4d5ec-db2e-4900-bfd2-963a4e258fde",
        "amount": {
            "value": -5250,
            "currency": "EUR"
        },
        "bookingDate": "2018-10-13T12:00:00Z",
        "valueDate": "2018-10-13T12:00:00Z",
        "creditor": "Rundfunk ARD, ZDF, DRadio",
        
    },

]

Quick Start Setup Wizard

Overview

Another way to set up a bank access with ahoi is to use the setup wizard. The wizard can be opened in a browser and asks the user for all required information. You still need to get an installation and banking token first.

Step 1: Get banking token

Requires the same steps as described in "Quick Start Basic" steps 1 to 4.

Step 2: Register with wizard

When you have your banking token you need to call the wizards registration endpoint to start the setup wizard.

Request without redirect URL

POST /onboarding-backend/api/v1/registration HTTP/1.1

You can supply a URL to redirect to once the wizard is finished. When redirecting a state parameter will be added as request parameter, which can have the value success, failure or canceled in order to indicate the process' result.

Request with redirect URL

POST /onboarding-backend/api/v1/registration HTTP/1.1

{
  "redirectUrl": "https://your.host:port/path"
}

The wizard will let the user select which accounts should be registered with ahoi. To restrict this to a certain type of account you can supply a list of expected account types. All other accounts will be ignored. In addition, the use case can be specified. In this case we want to set up a registration, so we can add the use case SetupRegistrationRequestDto. This is also the default and therefor optional for this case.

Request with redirect URL and account restriction

POST /onboarding-backend/api/v1/registration HTTP/1.1

{
  "usecase": "SetupRegistrationRequestDto",
  "redirectUrl": "https://your.host:port/path"
  "accountKinds": [
    "GIRO"
  ]
}

Which ever variant you use, it will return a json object containing the URL to start the wizard.

Step 3: Open frontend

Open the URL from the registration response in a browser and continue setup there.

Once finished the wizard will redirect to the URL https://your.host:port/path/?state=success, for example.

Quick Start Account Refresh

Overview

An account refresh in wallis.Multibank retrieves latest transactions from the bank and updates the account balance.

These are the steps to execute the account refresh using wallis.Multibank without webhook notifications:

  1. Trigger the account refresh
  2. Poll the task state
  3. (in case of a required TAN) Fetch the TAN challenge
  4. (in case of a required TAN) Submit the TAN
  5. Fetch refreshed account / transactions

STEP 1: Trigger the account refresh

The first step in executing a single account refresh using wallis.Multibank is to trigger it. As a response you will receive a task, which indicates the current state of the account refresh.

An account refresh can be triggered via the "refresh account" endpoint.

Request

PUT /ahoi/api/v2/accesses/<ACCESS_ID>/accounts/<ACCOUNT_ID>/refresh HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8

{
   "type": "AccountRefreshTask",
   "origin": "VAULT",
   "state": "CREATED",
   "cause": "NONE",
   "id": "<TASK_ID>",
   "bankMessages": [],
   "accountId": "<account_Id>",
   "accessId": "<access_Id>"
}

STEP 2: Poll the task state

The second step is to poll the task state. Therefore you need to query the task resource using the <TASK_ID> returned in the response to the first step.

The task status is polled via the "fetch state of task" endpoint.

Request

GET /ahoi/api/v2/tasks/<TASK_ID> HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Poll for the task until its state leaves IN_PROGRESS. After this two things can happen. Either the task results in a SUCCESS, then you can directly go to STEP 5. Or the tasks results in ACTION_REQUIRED, then you have to provide a TAN.

Response (Case #1: SUCCESS)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "AccountRefreshTask",
  "origin": "VAULT",
  "state": "SUCCESS",
  "cause": "NONE",
  "id": "<TASK_ID>",
  "bankMessages": null,
  "accountId": "<ACCOUNT_ID>",
  "accessId": "<ACCESS_ID>"
}

Response (Case #2: ACTION_REQUIRED)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "AccountRefreshTask",
  "origin": "VAULT",
  "state": "ACTION_REQUIRED",
  "cause": "AUTHORIZATION_REQUIRED",
  "id": "<TASK_ID>",
  "bankMessages": null,
  "accountId": "<ACCOUNT_ID>",
  "accessId": "<ACCESS_ID>"
}

STEP 3: Fetch the TAN challenge

If you have to provide a TAN ("cause": "AUTHORIZATION_REQUIRED"), the third step is to fetch the TAN challenge provided by the bank which is executing the account refresh. The challenge is required to provide the proper TAN authorization method.

Task challenges are obtained via the "fetch task challenge" endpoint. You can find a challenge for the wallis.Multibank Sandbank in the example response below.

Request

GET /ahoi/api/v2/tasks/<TASK_ID>/authorizations/challenges HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "SimpleAuthorizationRequest"
  "challenge": "Bitte geben Sie die TAN ***123456*** für den SandboxConnector ein!",
  "additionalInformation": "Zahlung an: DE978370501980020008850 Betrag: 0,10 EUR"
}

To make things easier for you we send you the expected TAN in our test environment inside the challenge field, so you can directly use it for the next step. With real bank accounts you would get a description where you find your TAN (e.g. "Bitte geben Sie ihre smsTAN ein.") or information to initialize the TAN generation on special device (e.g. chipTAN or photoTAN).

STEP 4: Submit the TAN

The fourth step is to supply the TAN authorization via REST-API.

Request via REST-API

For TAN providing via API, use the "authorize a task" endpoint.

PUT /ahoi/api/v2/tasks/<TASK_ID>/authorizations/challenges HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

{
  "type": "TanAuthorizationResponse"
  "response": "<TAN>"
}

More details on the Authorization process can be found in the "SCA handling" section

Response (SUCCESS)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "AccountRefreshTask",
  "id": "<TASK_ID>",
  "origin" : "VAULT",
  "state": "SUCCESS",
  "cause": "NONE",
  "bankMessages": []
}

Response (FAILED, because TAN was invalid)

{
  "type": "TransferTask",
  "id": "<TASK_ID>",
  "state": "FAILURE",
  "cause": "AUTHORIZATION_WRONG",
  "bankMessages": [
    {
      "level": "ERROR",
      "message": "Die TAN ist falsch!",
      "errorCode": "TAN_INVALID"
    }
  ]
}

STEP 5: Fetch the refreshed account / transactions

After the account is refreshed, you can retrieve it. Just use the account resource as shown below (e.g., if you want to view your account balance) or you can fetch the latest transactions via the transaction resource.

Request

GET /ahoi/api/v2/accesses/<ACCESS_ID>/accounts/<ACCOUNT_ID> HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
  {
    "id": "<ACCOUNT_ID>",
    "name": "Checking Account",
    "userDefinedName": "My Checking Account",
    "owner": "Max Mustermann",
    "providerId": 0,
    "kind": "GIRO",
    "automaticRefreshInterval": 3600,
    "type": "BankAccount",
    "number": "0317899806",
    "bankCodeNumber": "99994000",
    "bic": "TESTBICXXXX",
    "iban": "DE00999940000317899806",
    "currency": "EUR",
    "balance": {
      "amount": {
        "value": 133723,
        "currency": "EUR"
      },
      "date": "2016-10-24T13:37:00+02:00"
    }
  }
]

Account Refresh via wizard

Just like the setup, the wizard can also be used to let the user trigger a refresh via UI. This works in most parts like the setup wizard. You should already have an installationID, so that part can be skipped. When registering with the wizard you must add a use case to your request to indicate, that you want to do a refresh, no setup.

Request with refresh use case

POST /onboarding-backend/api/v1/registration HTTP/1.1

{
  "usecase": "RefreshRegistrationRequestDto",
  "redirectUrl": "https://your.host:port/path"
}

Quick Start Transfer

Overview

Steps to execute a single SEPA transfer using wallis.Multibank without webhook notifications:

  1. Submit the SEPA transfer
  2. Poll the task state
  3. Fetch the TAN challenge
  4. Submit the TAN

STEP 1: Submit the SEPA transfer

The first step in executing a single SEPA transfer using wallis.Multibank is to submit a new transfer from one of your accounts that corresponds to your access.

Transfers are created via the "create a new transfer" endpoint.

Request

POST /ahoi/api/v2/accesses/<ACCESS_ID>/accounts/<ACCOUNT_ID>/transfers HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>
Content-Type: application/json

{
    "iban" : "<IBAN>",
    "bic" : "TESTBICXXXX",
    "name" : "Stan S. Stanman",
    "amount" : {
        "value" : 5000,
        "currency" : "EUR"
    },
    "purpose" : "Test"
}

Response

HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8

{
   "type" : "TransferTask",
   "id" : "<TASK_ID>",
   "origin" : "VAULT",
   "state" : "CREATED",
   "cause" : "NONE",
   "bankMessages" : []
}

STEP 2: Poll the task state

The second step is to poll the task state until the TAN challenge is available. To get the current state of the transfer task, you need to query the task resource using the <TASK_ID> returned in the response to the first step.

Request

GET /ahoi/api/v2/tasks/<TASK_ID> HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response (success)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "type": "TransferTask",
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "ACTION_REQUIRED",
    "cause": "AUTHORIZATION_REQUIRED",
    "bankMessages": []
}

Response (error)

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "TransferTask",
  "id": "<TASK_ID>",
  "origin": "VAULT",
  "state": "FAILURE",
  "cause": "BANK_COMMUNICATION_FAILED",
  "bankMessages": [
    {
      "level": "ERROR",
      "message": "Unerwarteter Fehler: TAN request response loop ran into timeout!",
      "errorCode": "UNCLASSIFIED"
    }
  ]
}

STEP 3: Fetch the TAN challenge

The third step is to fetch the TAN challenge provided by the bank that is executing the SEPA transfer. The challenge is required to provide the proper TAN authorization method.

Task challenges are obtained via the "fetch task challenge" endpoint. You can find a challenge for the wallis.Multibank Sandbank in the example response below.

Request

GET /ahoi/api/v2/tasks/<TASK_ID>/authorizations/challenges HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "SimpleAuthorizationRequest"
  "challenge": "Bitte geben Sie die TAN ***123456*** für den SandboxConnector ein!",
  "additionalInformation": "Zahlung an: DE978370501980020008850 Betrag: 0,10 EUR"
}

To make things easier for you, we send you the expected TAN in our test environment inside the challenge field, so you can directly use it for the next step. With real bank accounts you would get a description where you find your TAN (e.g. "Bitte geben Sie ihre smsTAN ein.") or information to initialize the TAN generation on special device (e.g. chipTAN or photoTAN).

STEP 4: Submit the TAN

The fourth step is to supply the TAN authorization, which is done via the "authorize a task" endpoint.

Request

PUT /ahoi/api/v2/tasks/<TASK_ID>/authorizations/challenges HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

{
  "type": "TanAuthorizationResponse",
  "response": "<TAN>"
}

More details on the authorization process can be found in the "SCA handling" section

Transfer SUCCESS

{
    "type": "TransferTask",
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "SUCCESS",
    "cause": "NONE",
    "bankMessages": []
}

Transfer FAILURE

{
  "type": "TransferTask",
  "id": "<TASK_ID>",
  "origin": "VAULT",
  "state": "FAILURE",
  "cause": "BANK_COMMUNICATION_FAILED",
  "bankMessages": [
    {
      "level": "ERROR",
      "message": "Unerwarteter Fehler: TAN request response loop ran into timeout!",
      "errorCode": "UNCLASSIFIED"
    }
  ]
}

Transfer failed authorization (TAN invalid)

{
    "type": "TransferTask",
    "id": "<TASK_ID>",
    "origin": "VAULT",
    "state": "FAILURE",
    "cause": "AUTHORIZATION_WRONG",
    "bankMessages": [
        {
            "level": "ERROR",
            "message": "Die TAN ist falsch!",
            "errorCode": "TAN_INVALID"
        }
    ]
}

Quick Start Webhook

Webhooks are used to deliver notifications about events within wallis.Multibank that you or your users can respond to. For now these events consist of transfer-related actions, such as providing an answer to a challenge (e.g., a TAN).

You will also receive a notification when new transactions are detected in accounts that have already been set up.

Overview

To receive webhook-based notifications, please complete the following steps:

  1. Create a publicly available endpoint for wallis.Multibank webhooks
  2. Register your endpoint URL with the wallis.Multibank Sandbox Manager
  3. Send a test event
  4. Try triggering an event

STEP 1: Webhook endpoint

Your webhook endpoint must be able to receive POST requests with Content-Type: application/json. The body will contain a JSON object in the following format for events concerning a transfer task:

{
    "type": "TransferTaskWebhookMessage",
    "event": "TASK_AUTHORIZATION_REQUIRED",
    "clientId": "<CLIENT_ID>",
    "userContextId": "<CONTEXT_ID>",
    "taskId": "<TASK_ID>",
    "state": "ACTION_REQUIRED",
    "cause": "AUTHORIZATION_REQUIRED"
}

As a response we expect you to reply with the HTTP status code 202 (Accepted). Please queue the message and process it asynchronously instead of immediately starting to process it before you send us the reply.

You can find a swagger specification for the model and REST endpoint. Try generating your server code using the swagger editor.

STEP 2: Register

Log in to your Sandbox Manager account and visit your user profile. Here you can enter the URL to which we will send webhook notifications.

Sandbox Manager Webhook Registration

STEP 3: Send a test event

Once you have entered the webhook URL and ensured that your endpoint is available, you can use the "Verify" button to send a test request.

STEP 4: Try triggering an event

You can try and create a transfer using wallis.Multibank and see if you receive a TASK_AUTHORIZATION_REQUIRED webhook event asking you to enter a TAN challenge. After you have successfully provided one, you should receive the message TASK_SUCCESS.

For more details please refer to the section Webhooks.

SCA handling

SCA stands for "Strong Customer Authentication". The bank can request an SCA for any type of transaction. Your software needs to handle and respond to those requests through wallis.Multibank.

Authentication is required when the task for your transaction enters the state ACTION_REQUIRED with cause AUTHORIZATION_REQUIRED or AUTHORIZATION_METHOD_REQUIRED. The latter indicates, that the desired method needs to be selected first. This case will only occur if the user has more than one authorization method activated for his access.

Setting the authorization method

When your task enters state ACTION_REQUIRED with cause AUTHORIZATION_METHOD_REQUIRED the user needs to select an authorization method. The first step for this is to get the possible methods via the "Fetch authorization methods" endpoint.

Get method list

Request

GET /ahoi/api/v2/tasks/<TASK_ID>/authorizations/methods HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

The response will contain a list of authorization methods (at least 2).

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
  {
    "methodId": "QR",
    "type": "PHOTO_OTP",
    "version": "HHD1.3.2QR",
    "name": "chipTAN QR | Kartennummer: ******0430",
    "explanation": "Übertragung der Auftragsdaten mittels QR-Code. Erfordert geeigneten TAN-Generator."
  },
  {
    ...
  }
]

Set selected method

After selecting one of the methods, you must set this method for your transaction. This is done via the "Select authorization method" endpoint.

Request

PUT /ahoi/api/v2/tasks/<TASK_ID>/authorizations/methods HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

{
  "methodId": "QR",
  "type": "PHOTO_OTP",
  "version": "HHD1.3.2QR",
  "name": "chipTAN QR | Kartennummer: ******0430",
  "explanation": "Übertragung der Auftragsdaten mittels QR-Code. Erfordert geeigneten TAN-Generator."
}

Everything but methodId and name is optional in this request.

The response will be an HTTP code 202 without body.

Response

HTTP/1.1 202 OK
Content-Type: application/json; charset=utf-8

Authorize transaction

After choosing the method (or if there was only one option) the user must authorize the transaction. Most authorization methods include entering a TAN by the user. How the user gets the necessary TAN depends on the method. wallis.Multibank supports simple TAN methods like smsTAN, where all the frontend has to do is offer an input field for the TAN, as well as authorization methods using an image/QR code or a decoupled workflow where the authorization is supplied by other means than wallis.Multibank (e.g. an app from the user's bank).

Get the SCA Challenge

Before sending the authorization, the sca challenge must be read from wallis.Multibank. This is done via the "Fetch task challenge" endpoint. The request is a simple GET including the authorization header.

Request

GET /ahoi/api/v2/tasks/<TASK_ID>/authorizations/challenges HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

The response is the challenge received from the bank. Depending on the used method the supplied data may differ slightly.

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "SimpleAuthorizationRequest",
  "challenge": "Bitte geben Sie die TAN ***123456*** für den SandboxConnector ein!",
  "additionalInformation": "Zahlung an: DE978370501980020008850 Betrag: 0,10 EUR"
}

What information the response contains depends on the type of challenge, which is defined by the type field. All challenges contain the challenge text. Additional information about the transaction may be contained if supplied by the bank. The provided example is from our Sandbank which sends the expected TAN as part of the challenge.

The type can be one of the following * SimpleAuthorizationRequest: This type of challenge contains no further fields. The TAN has to come from somewhere else. Most common way nowadays is probably a mobile app that provides the TAN. * ChiptanOpticAuthorizationRequest: In addition to the challenge and additionalInformation fields these types also contain a code. That code must be converted into the appropriate image for the user. * ImageExternalAuthorizationRequest: Authorization by image requires the frontend to display that image for the user to generate the TAN. In this case only an external link to the image is supplied. * ImageEmbeddedAuthorizationRequest: In contrast to the external image, this type of challenge includes the image embedded in the response. * DecoupledAuthorizationRequest: Decoupled challenges are special in the way, that they don't require a TAN to be send back to wallis.Multibank. The authorization for the transaction is supplied by other means, like a mobile app. wallis.Multibank still requires a response after the user confirmed to have authorized the transaction so that the backend can start polling the bank's servers until authorization is confirmed. * RedirectAuthorizationRequest: Redirect challenges redirect the user to a bank website, where they enter their credentials. The bank will then redirect the user back to the wallis.Multibank frontend and provide a special code that will then be used for authorization against the bank's API.

Submit Authorization

If the user entered a TAN, it is sent to wallis.Multibank via the "Authorize a task" endpoint.

Response with TAN

PUT /ahoi/api/v2/tasks/<TASK_ID>/authorizations/challenges HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>

{
  "type": "TanAuthorizationResponse",
  "response": "123456"
}

The response field contains the entered TAN, the type field is optional at this point as TanAuthorizationResponse is the default value.

If you are using a decoupled or redirect SCA workflow no TAN is sent but the type field must be set accordingly.

Decoupled Authorization Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "DecoupledAuthorizationResponse"
}

Redirect Authorization Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "type": "RedirectAuthorizationResponse",
  "code": "<authorization code from the bank taken from redirect callback>",
  "state": "<string for request tracking, taken from redirect callback>",
  "error": null,
  "errorDescription": null
}

The Server will return a 202 response.

Response

HTTP/1.1 202 OK
Content-Type: application/json; charset=utf-8

How to Use Extended Encryption

Overview

Here are the steps to carry out a registration with extended encryption using wallis.Multibank:

  1. Get a registration token
  2. Retrieve a public key
  3. Create X-Ahoi-Session-Security header
  4. Request a registration
  5. Extract the installationId
  6. Encrypt the X-Authorization-Ahoi header to fetch a banking token

STEP 1: Get a registration token

This step is identical to the step outlined in the Quick Start.

Please copy your clientId and clientSecret from the AHOI Sandbox Manager and encode them using the Base64 algorithm to a single string as depicted below.

Example: Encode basic auth credentials in Java

String credentials = String.format("%s:%s", <clientId>, <clientSecret>);
byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
String AUTH_BASIC_BASE64 = Base64.getEncoder().encodeToString(credentialsBytes);

Send this to the OAuth service using the following request. This should result in a response similar to the one shown below.

Request

POST /auth/v1/oauth/token?grant_type=client_credentials HTTP/1.1
Authorization: Basic <AUTH_BASIC_BASE64>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "access_token": "<REGISTRATION_TOKEN>",
    "token_type": "bearer",
    "expires_in": 1199,
    "scope": "ANON",
    "jti": "c6d69c1c-3f57-417b-82d6-0f288f38ef65"
}

STEP 2: Retrieve a public key

When communicating with AHOI and using extended encryption, the additional X-Ahoi-Session-Security header needs to be added to each request in which sensitive information is transmitted.

The session security header needs to be encrypted with an AHOI public key fetched in this step.

Request

GET /ahoi/api/v2/registration/keys HTTP/1.1
Authorization: Bearer <REGISTRATION_TOKEN>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "keyId": "<KEY_ID>",
    "validUntil": "2018-10-11T16:00:00Z",
    "publicKey": {
        "value": "<KEY>",
        "specification": "RSA_2048_SHA1"
    },
    "publicKeySignature": { 
        "value": "<KEY_SIGNATURE>",
        "specification": "SHA1_WITH_RSA"
    }
}
Identifier Description
RSA_2048_SHA1 RSA private / public key with 2048-bit key length and OAEP padding. ("RSA/ECB/OAEPWithSHA-1AndMGF1 Padding")
SHA1_WITH_RSA SHA1 signature with RSA private / public key with 2048-bit key length and PKCS1 padding. ("SHA1withRSA")

STEP 3: Create an "X-Ahoi-Session-Security" header

Why is the X-Ahoi-Session-Security request header necessary? Sensitive data like the PIN or the installationId are protected by HTTPS transport security and encrypted by a symmetricKey for each session you create while using extended encryption. This symmetricKey must be encrypted using an asymmetric public key, fetched in the previous step before it is send as the "sessionKey" in the X-Ahoi-Session-Security header.
The session key is used to encrypt and later to decrypt the sensitive user data in wallis.Multibank and vice versa.

The necessary steps to build the header are:

  1. Generate the symmetric key (AES)
  2. Decode the public key received from AHOI
  3. Encrypt the symmetric key with the AHOI public key to secure the session key
  4. Encode the session key with Base64URL
  5. Build the JSON string containing publicKeyId, sessionKey and keySpecification
  6. Encode the JSON string using Base64URL to create the header value

Example: How to create the "X-Ahoi-Session-Security" header in Java

// 1. Generate a simple symmetricKey
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256);
SecretKey key = generator.generateKey();
byte[] symmetricKey = key.getEncoded();

// 2. Decode and parse PublicKey
byte[] data = Base64.getUrlDecoder().decode(<KEY>);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(data));

// 3. Encrypt symmetricKey with the recieved public key
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedsymmetricKey = cipher.doFinal(symmetricKey);

// 4. Encode Base64 url-safe
Base64.Encoder base64UrlEnocder = Base64.getUrlEncoder().withoutPadding(); 
String sessionKey = base64UrlEncoder.encodeToString(encryptedsymmetricKey);

// 5. Build JSON string
String headerTemplate = "{\"publicKeyId\":\"%s\",\"sessionKey\":\"%s\",\"keySpecification\":\"AES\"}";
String header = String.format(headerTemplate, <KEY_ID>, sessionKey);
byte[] headerBytes = header.getBytes(StandardCharsets.UTF_8);

// 6. Now encode JSON to create header value
String BASE64_ENCODED_JSON_HEADER = base64UrlEnocder.encodeToString(headerBytes);

STEP 4: User registration

After the X-Ahoi-Session-Security request header has been built, the registration request is submitted as detailled below. The corresponding response contains an encrypted installationId.

User registration is done via the "user registration" endpoint.

Request

POST /ahoi/api/v2/registration HTTP/1.1
Authorization: Bearer <REGISTRATION_TOKEN>
X-Ahoi-Session-Security: <BASE64_ENCODED_JSON_HEADER>

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "installation":"<ENCRYPTED_INSTALLATION_ID>"
} 

STEP 5: Extract installation ID with session key (your symmetricKey)

The decryption of the installationId from the registration response with your symmetric key is shown below.

Example: Decrypt response in Java

// 1.Decode the base64 url-safe data
byte[] encryptedInstallation = Base64.getUrlDecoder().decode(<ENCRYPTED_INSTALLATION_ID>);

// 2.Decrypt with your symmetricKey
byte[] iv = new byte[16];
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.DECRYPT_MODE, secKey, new IvParameterSpec(iv));
String installationId = new String(cipher.doFinal(encryptedInstallation), "UTF-8");

STEP 6: Encrypt "X-Authorization-Ahoi" header to fetch the banking token

In the event that extended encryption is enabled, the X-Authorization-Ahoi needs to be encrypted, too. This header is used to request a banking token from the wallis.Multibank OAuth service.

We will skip the instructions here on how to create nonce and timestamp values for the header string. This is described in STEP 4 of the Quick Start.

Accesses are created via the "get a new access" endpoint.

Example: Encrypt "X-Authorization-Ahoi" header in Java

String xAuthorizationAhoiHeader = "{ \"installationId\": \"<INSTALLATION_ID>\", \"nonce\": \"<nonce>\", \"timestamp\": \"<JAVA_TIMESTAMP>\" }";

// encrypt header value
byte[] key = Base64.getUrlDecoder().decode(<appSecretKey>);
byte[] iv = Base64.getUrlDecoder().decode(<appSecretIV>);
SecretKey secKey = new SecretKeySpec(key, SymmetricAlgorithm.AES_256.getAlgorithm());
Cipher cipher = Cipher.getInstance(SymmetricAlgorithm.AES_256.getTransformation());
cipher.init(1, secKey, new IvParameterSpec(iv));
byte[] encryptedJson = cipher.doFinal(xAuthAhoiJson.getBytes(StandardCharsets.UTF_8));
// encode encrypted header value
String XAUTH_AHOI_BASE64_URL_ENC = Base64.getUrlEncoder().withoutPadding().encodeToString(encryptedJson);

STEP 7: Create an access

When creating an access with extended encryption enabled, is slightly different than described in STEP 7 of Basic Quick Start Beside the need to supply the X-Ahoi-Session-Security header, the credentials must be encrypted using your symmetricKey.

Example: Encrypt access credentials in Java

byte[] iv = new byte[16];
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secKey = new SecretKeySpec(symmetricKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secKey, new IvParameterSpec(iv));

byte[] enc_username = cipher.doFinal("meinAnmeldename".getBytes(StandardCharsets.UTF_8));
byte[] enc_pin = cipher.doFinal("meinePin".getBytes(StandardCharsets.UTF_8));

String USER_ENC_BASE64 = Base64.getUrlEncoder().withoutPadding().encodeToString(enc_username);
String PIN_ENC_BASE64 = Base64.getUrlEncoder().withoutPadding().encodeToString(enc_pin);

Here is an example of how the request to wallis.Multibank might look when creating an access with extended encryption enabled.

Request

POST /ahoi/api/v2/accesses/async HTTP/1.1
Authorization: Bearer <BANKING_TOKEN>
X-Ahoi-Session-Security: <BASE64_ENCODED_JSON_HEADER>
Content-Type: application/json

{
  "type" : "BankAccess",
  "providerId" : "<PROVIDER_ID>",
  "accessFields" : {
    "USERNAME" : "<USER_ENC_BASE64>",
    "PIN" : "<PIN_ENC_BASE64>"
  }
}

wallis.Multibank Resources

This section provides a brief overview of the various key components of wallis.Multibank. If you're uncertain about what a resource actually represents, please begin by consulting this section.

AHOI Resources

App service

Your app-specific service that connects to wallis.Multibank.

Installation

An installation represents one context for user-specific data.

Access

An access represents a login to an assigned provider (e.g., login credentials for online banking). It includes data such as the username and PIN. Which fields are required will be described in the provider's input field descriptions.

Each access has a validation state that describes the validity of the credentials. This state might change over time if the credentials are no longer valid.

Account

An account is a grouping of financial records (e.g., a bank account). It contains information about the account name, the account holder, the account type as well as related information such as the account number, IBAN or account balance. It is associated with one or more accesses.

An automatic background refresh of transactions can be activated for every account.

Provider

A provider represents financial institutions wallis.Multibank can connect to (e.g., banks).

Transaction

A transaction represents a financial operation associated with an account. A bank account transaction contains information about the payee and the creditor, the amount, the date on which it was booked, the availability of funds and its purpose.

Task

A task represents a job which will be processed by wallis.Multibank asynchronously and possibly in multiple steps. Each task has an id, origin, state, cause and may contain bank messages.

Origin

The origin of a task is an enumeration and can either be VAULT or PLAIN. Vault tasks require user resources to be set up within wallis.Multibank, whereas plain tasks work without setting them up previously.

State

The state describes its tasks condition. It's an enumeration and may be CREATED, IN_PROGRESS, ACTION_REQUIRED, SUCCESS, FAILURE or UNKNOWN.

                     ┌─────────────────────┐
                     v                     │
CREATED ───┬──> IN_PROGRESS ───┬──> ACTION_REQUIRED ───┬──> SUCCESS
           │                   │                       │
           └───────────────────┴───────────────────────┼──> FAILED
                                                       │
                                                       └──> UNKNOWN

CREATED

The task has been created successfully but processing has not been started.

IN_PROGRESS

The task is currently being processed, wait until it leaves this state.

ACTION_REQUIRED

The task is at a point where it requires user interaction, refer to its cause for details.

SUCCESS

The task has been completed successfully.

FAILURE

There has been an error and the task has failed. The cause and/or bank messages might contain additional information.

UNKNOWN

Something unexpected has happened and the task has failed, please contact us.

Cause

A cause offers additional insight to tasks which are in the ACTION_REQUIRED or FAILURE state. It's an enumeration and all possible values are listed below.

NONE

There is no cause. This is the usual cause whenever the task is not in ACTION_REQUIRED state.

PROVIDER_SELECTION_REQUIRED

The task requires the selection of a provider (e.g. a bank institute) to be able to continue. Get information about available providers via the "get available providers" endpoint. Provide the selected provider by sending a request to the "select provider" endpoint of your task.

PROVIDER_SELECTION_FAILED

Provider selection failed.

LOGIN_REQUIRED

The task requires a login to be able to continue. Login information from the provider is available via the "fetch login information" endpoint. Provide username and pin by sending a request to the "provide login information" endpoint of your task.

AUTHORIZATION_METHOD_REQUIRED

The financial institution has offered a choice of multiple TAN authorization methods and the task requires a selection. The available authorization methods are accessible via the "fetch authorization methods" endpoint, while the selection itself is done via the "select authorization method" endpoint.

AUTHORIZATION_REQUIRED

The task requires an TAN authorization. The challenge is available via the "fetch task challenge" endpoint. Task authorization is done via the "authorize a task" endpoint.

ACCOUNT_SELECTION_REQUIRED

The task requires the selection of one or more accounts to be able to continue. Get information about available accounts via the "get available accounts" endpoint. Provide the selected accounts by sending a request to the "select accounts" endpoint of your task.

ACCOUNT_SELECTION_FAILED

Account selection failed.

INTERNAL_ERROR

wallis.Multibank has run into an internal error and can't continue with the task processing.

BANK_COMMUNICATION_FAILED

There are technical problems with the communication to the server of the provider.

NO_BANK_TASK_CREATED

The task is in an invalid state which prevents wallis.Multibank from starting the communication with the provider (e.g., transfer from an account which does not support transfers).

ACCESS_WRONG

Selected access is invalid.

ACCESS_LOCKED

Selected access is locked.

BAD_REQUEST

Unable to continue with the task as the request is invalid (e.g., wallis.Multibank doesn't support the requested task for the selected provider).

LOGIN_WRONG

Authentication failed because the provided credentials are invalid.

AUTHORIZATION_METHOD_WRONG

Authorization method selection failed.

AUTHORIZATION_FAILED

Authorization failed due to unspecified problems.

AUTHORIZATION_WRONG

Authorization failed because the provided TAN is invalid.

UNKNOWN

Something unexpected has happened and the task has failed, please contact us.

Bank Messages

A list containing the messages from the financial institute.

Webhooks

All webhook events contain the information you need to access the related data.

The clientId is equal to your client id you need, when you request an oauth token from our authorization server.

The userContextId is equal to the context_id you get when you request your banking token as part of the JSON response.

Type Events Triggered by
AccessSetupTaskWebhookMessage
AccessUpdateTaskWebhookMessage
AccountRefreshTaskWebhookMessage
AccountsFetchTaskWebhookMessage
AuthorizationMethodRefreshTaskWebhookMessage
TanSchemeRefreshTaskWebhookMessage
TransferTaskWebhookMessage
TASK_SUCCESS
TASK_FAILURE
TASK_LOGIN_REQUIRED
TASK_AUTHORIZATION_REQUIRED
TASK_AUTHORIZATION_METHOD_REQUIRED
The corresponding task state transition initiated by a user
AccountsRefreshTaskWebhookMessage TASK_SUCCESS
TASK_FAILURE
TASK_LOGIN_REQUIRED
TASK_AUTHORIZATION_REQUIRED
TASK_AUTHORIZATION_METHOD_REQUIRED
The corresponding task state transition initiated by automatic updates in AHOI
AccountWebhookMessage ACCOUNT_NEW_TRANSACTIONS New transactions found for the given account id, can be from automatic updates or user actions
TestWebhookMessage TEST Test webhook message to verify the communication link, can be triggered on demand

wallis.Multibank Explorer Tutorial

The API Explorer is integrated directly into the wallis.Multibank documentation. Follow the steps below to experience your first success with the API Explorer:

  1. Open your Sandbox Manager so you can see your service-specific credentials.

  2. Open the API Explorer in a second browser tab.

  3. Copy your credentials (clientId, clientSecret, appSecretIV and appSecretKey) from the Sandbox Manager into the respective fields in the API Explorer in the sidebar located on the left.

  4. Click on Get Registration Token. This obtains a registration token that appears in the Token field.

  5. Select Registration in the menu on the left, then User Registration, and finally select TRY for this endpoint. The previously anonymous user will now be registered and that user's installationId will be displayed. You don't have to remember the installationId — just close the pop-up. The API Explorer will automatically put the variable into the corresponding field in the sidebar on the left. The Explorer has also automatically fetched a banking token for you, so you can now access all banking-specific wallis.Multibank endpoints. Congratulations!

  6. Set up your wallis.Multibank Sandbank access in wallis.Multibank. To do this, first take note of your wallis.Multibank Sandbank credentials (blz, username, pin) in the Sandbox Manager. Then switch to Provider in the menu and select List bank providers. Insert the bank code of the wallis.Multibank Sandbank (99994000) into the bankCode field and execute the request with TRY.

  7. As a result, you've now received an id for the provider. Next, select Access in the menu and then select the Create a new access endpoint. By clicking on the JSON body sample on the right, you can add an accessDto to your request. Replace the values in the providerId, USERNAME and PIN fields with your own values, delete the entry for CUSTOMERNUMBER and then execute the request. In response, you should get an HTTP status code 202 with an AccessSetupTask object with an id and state CREATED (refering to the task state).

  8. Use the Task menu and select Fetch state of task. Enter the given task id and click TRY. Repeat this while the state is not SUCCESS (or FAILURE). In the positive case there should be the accessId field filled with a UUID for you to continue and try further endpoints.

Your bank account is now successfully set up and wallis.Multibank has retrieved the account data for the wallis.Multibank Sandbank. And you also have all the other banking endpoints such as Get Account or List Transactions at your fingertips. Just give it a try!

FAQ

Banks

Which banks are currently supported within the sandbox system?

Right now, you can only use the wallis.Multibank Sandbank.

Why can I only use "wallis.Multibank Sandbank" within the sandbox system?

To provide access to real bank accounts, registration with the BaFin is required.

Which banks does wallis.Multibank support?

Currently wallis.Multibank supports all banks that offer FinTS with PIN and TAN. These include the savings and cooperative banks as well as most private banks. One exception is Commerzbank.

Which banks will wallis.Multibank connect to in the future?

How do I set up a bank access?

Accounts

My accounts are gone. What happened?

Why do I always have to re-register with wallis.Multibank to see my account?

You don't! When you register, you receive an installationId, which you have to save. The next time you return, you can use this installationId without having to re-register and you can then access your data again.

To manage data for multiple users/installations, you will have to create your own mapping of the users/installation to the corresponding installationId.

What account types does wallis.Multibank support?

wallis.Multibank basically supports giro-type (i.e., current, checking) and securities accounts. Both account types are also offered by the wallis.Multibank Sandbank.

What account types are still planned in wallis.Multibank?

Here, too, we are guided by the needs of our customers and will implement new types of accounts provided that there is sufficient demand for them.

Transactions

How do I get new transactions from my bank?

There are two ways to get new transactions from your bank (as well as from the wallis.Multibank Sandbank).

  1. wallis.Multibank will automatically update the accounts for a given installationId every other hour.

  2. To force a manual refresh use the resource POST /accesses/{ACCESS_ID}/accounts/{ACCOUNT_ID}/refresh. You will receive a task and once the state is SUCCESS your account will be up to date.

Why am I not receiving new transactions in my wallis.Multibank Sandbank accounts?

The wallis.Multibank Sandbank accounts currently only create transactions when you register with the Sandbox Manager. New transactions are not generated on an ongoing basis. However, you can generate your own transactions:

  1. By creating transfers to these accounts via wallis.Multibank. For example, if you transfer money from one demo account to another demo account, corresponding transactions are created.

  2. You have the possibility to create transactions directly in the Sandbox Manager for a demo account.

  3. If you want to have a new account, delete one of your maximum of five (5) accounts and create a new account based on a selected target group in your Sandbox Manager.

  4. If you would like to fill your account with new transactions (if, for example, the last transaction is 30 days old), you can also do this in the Sandbox Manager.

Payment transactions / bank transfers / direct debits

What kind of payment transactions does wallis.Multibank currently support?

wallis.Multibank does not currently offer any payment transactions for actual accounts. You can only perform a bank transfer with our demo accounts for testing and integration purposes. We are working on support for real-world accounts.

Managing my Sandbox Manager access

I forgot my password for the Sandbox Manager. What do I do?

No problem! You can use our "Forgot password" function to securely request a new password. You will then receive an e-mail with detailed reset instructions.

I want to delete / log out / deregister my sandbox access. How can I do that?

We're sorry to see you go, but it's still a very simple process. Just log into the Sandbox Manager. Under "Settings" you'll find a section titled "Delete your sandbox access".

I want to delete data in my sandbox account without deleting the sandbox account itself. How do I do that?

Simply log into the Sandbox Manager. You can:

a) delete a single installationId from the overview page at the bottom of the "Delete Installation Data" section, or

b) delete all installationIds and their associated data for a clientId at once. Consult the "Delete All Installation Data" section on the overview page.

Production use of wallis.Multibank

I want to use wallis.Multibank in one of my applications. What do I have to do?

It depends on your application. Please contact us via e-mail at ahoi-api@wallis.de. It helps if you're able to describe your application and the wallis.Multibank features you want to use as well as early quantitative factors (e.g., number of users, estimated number of updates per day, estimated number of new transactions), because this will enable us to better determine the costs.

Can I also use wallis.Multibank if I am not/do not have a company regulated by ZAG?

If you are only processing your own company's account data (e.g., incoming payment checks, statistics), we can offer you a solution. Simply contact us at ahoi-api@wallis.de — ideally with your contact details and a short description of what you would like to do, how many bank accounts are involved and how many transactions might occur per day.

Can I use wallis.Multibank for my own application as a private individual?

No, private individuals are not allowed to use wallis.Multibank in production contexts. As a private individual, you are only allowed to use the sandbox with demo accounts.

Engineering / software development

Is there a client SDK for wallis.Multibank?

We can currently offer SDKs for Java and JavaScript. However, we are unable to provide any guarantee for these clients. The clients should help you to build your applications in a straightforward way.

Contact us via e-mail at ahoi-api@wallis.de with questions.

Is there a way for me to generate an wallis.Multibank client?

Yes, you can generate a client by using our swagger file, but you will have to do it yourself.

Security

Why does wallis.Multibank store my bank access credentials?

wallis.Multibank frequently attempts to refresh your accounts in order to provide you with up-to-date information as well as to inform you via notifications about new events such as transactions. If we had to request your credentials every time, this convenient and automated approach wouldn't be possible.

Why does the wallis.Multibank client have to encrypt certain data? Why is transport encryption via TLS insufficient?

Mobile devices in particular are often exposed to insecure networks where communication can be intercepted and surveilled. To avoid this, certain data has to be encrypted.

Are there any security requirements for clients that I want to provide to my customers?

Yes, we have security requirements for clients using the wallis.Multibank. However, these requirements only apply once the application goes live to your customers. On request, we can provide you with the "Security Standard for wallis.Multibank Clients" prior to the conclusion of the contract.

How is the encrypted JSON data encoded?

The encrypted JSON data must be serialized via Base64URL encoding (without padding) (see also the Quick Start section).

How can I tell wallis.Multibank to work with or without extended encryption?

Within the sandbox, you can turn this on or off in the Sandbox Manager via the "Advanced Encryption" setting. In a production environment this is configured by us for you (see also the first two questions regarding security above).

Technical

Do you support Cross-Origin Resource Sharing (CORS) requests?

wallis.Multibank is a server-to-server API and is not intended to be used directly from browser. If you want to use wallis.Multibank we expect you to connect to it via your own application service.

Are requests to wallis.Multibank rate-limited?

Yes, requests to wallis.Multibank (/ahoi/api/**) are rate-limited with a token-bucket implementation. Each user is limited to 100 requests per second and ip. Any additional requests will be rejected with a 429: Too Many Requests Error.

What does it mean when my account is locked?

After 3 successive failed login attempts an account gets locked for 15 minutes. This means that each login attempt will result in a 423: Locked.

Contact Us

Do you need assistance? Is anything unclear?

We're more than happy to help. Just send us an e-mail: ahoi-api@wallis.de

We also welcome your feedback on our documentation.

Glossary