AHOI
AHOI 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
AHOI offers traditional banking functionality alongside various transaction refinements.
You can use AHOI to:
- manage accesses
- manage portfolios
- obtain securities
- manage bank accounts
- issue SEPA transfers
- obtain transactions
- manage portfolios
Quick Start Basics
This Cookbook enables you to get started quickly with AHOI. Before you begin, please register for an AHOI Sandbank 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 AHOI endpoints and assists you with OAuth 2.0 authorization.
For general information about AHOI 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:
- Register with the AHOI Sandbank
- Get a registration token
- Register the user
- Get a banking token
- List all providers
- Get access data for selected providers
- Create an access for the user
- Get all accounts
- Get all transactions for the account
AHOI OAuth Flow
The AHOI OAuth flow (step 2 to 4) as sequence diagram.
STEP 1: Register with the AHOI Sandbank
The first step you need to complete before you can use AHOI is to register with the AHOI Sandbank. 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 AHOI Sandbank. 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 AHOI. 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 AHOI Sandbank. 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 AHOI 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 AHOI Sandbank 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 AHOI 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.
You can find a OpenAPI specification for the model and REST endpoints. Try generating your client code and models using the swagger editor.
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 AHOI retrieves latest transactions from the bank and updates the account balance.
These are the steps to execute the account refresh using AHOI without webhook notifications:
- Trigger the account refresh
- Poll the task state
- (in case of a required TAN) Fetch the TAN challenge
- (in case of a required TAN) Submit the TAN
- Fetch refreshed account / transactions
STEP 1: Trigger the account refresh
The first step in executing a single account refresh using AHOI 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 AHOI 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 die AHOI Sandbank 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 AHOI without webhook notifications:
- Submit the SEPA transfer
- Poll the task state
- Fetch the TAN challenge
- Submit the TAN
STEP 1: Submit the SEPA transfer
The first step in executing a single SEPA transfer using AHOI 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 AHOI 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 die AHOI Sandbank 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"
}
]
}
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 AHOI.
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. AHOI 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 AHOI (e.g. an app from the user's bank).
Get the SCA Challenge
Before sending the authorization, the sca challenge must be read from AHOI. 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 die AHOI Sandbank 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 AHOI. The authorization for the transaction is supplied by other means, like
a mobile app. AHOI 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 AHOI 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 AHOI 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
AHOI Resources
This section provides a brief overview of the various key components of AHOI. If you're uncertain about what a resource actually represents, please begin by consulting this section.
App service
Your app-specific service that connects to AHOI.
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 AHOI 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 AHOI 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 AHOI, 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
AHOI 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 AHOI 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., AHOI 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 |
AHOI Explorer Tutorial
The API Explorer is integrated directly into the AHOI documentation. Follow the steps below to experience your first success with the API Explorer:
Open your AHOI Sandbank so you can see your service-specific credentials.
Open the API Explorer in a second browser tab.
Copy your credentials (
clientId
,clientSecret
,appSecretIV
andappSecretKey
) from the AHOI Sandbank into the respective fields in the API Explorer in the sidebar located on the left.Click on
Get Registration Token
. This obtains a registration token that appears in theToken
field.Select
Registration
in the menu on the left, thenUser Registration
, and finally selectTRY
for this endpoint. The previously anonymous user will now be registered and that user'sinstallationId
will be displayed. You don't have to remember theinstallationId
— 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 AHOI endpoints. Congratulations!Set up your AHOI Sandbank access in AHOI. To do this, first take note of your AHOI Sandbank credentials (
blz
,username
,pin
) in the AHOI Sandbank. Then switch toProvider
in the menu and selectList bank providers
. Insert the bank code of the AHOI Sandbank (99994000
) into thebankCode
field and execute the request withTRY
.As a result, you've now received an
id
for theprovider
. Next, selectAccess
in the menu and then select theCreate a new access
endpoint. By clicking on the JSON body sample on the right, you can add anaccessDto
to your request. Replace the values in theproviderId
,USERNAME
andPIN
fields with your own values, delete the entry forCUSTOMERNUMBER
and then execute the request. In response, you should get an HTTP status code202
with anAccessSetupTask
object with anid
andstate
CREATED
(refering to the task state).Use the
Task
menu and selectFetch state of task
. Enter the given task id and clickTRY
. Repeat this while thestate
is notSUCCESS
(orFAILURE
). In the positive case there should be theaccessId
field filled with a UUID for you to continue and try further endpoints.
Your bank account is now successfully set up and AHOI has retrieved the account data for the AHOI 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 AHOI Sandbank system?
Right now, you can only use the AHOI Sandbank.
Why can I only use "AHOI Sandbank" within the AHOI Sandbank system?
You can use our AHOI Sandbank for testing purposes. Due to BaFin regulation we can allow access to real bank accounts only after you signed a dedicated contract with us. Contact us at ahoi-api@wallis.de for more details.
Which banks does AHOI support?
Currently, AHOI supports all banks that offer FinTS and increasingly more via XS2A API. The former include the savings and cooperative banks as well as most private banks.
Which banks will AHOI connect to in the future?
- Which banks we connect in the future depends on our customers' needs. Feel free to contact us if your bank is not yet supported.
- The PSD2 requires banks to provide certain interfaces. We are working on supporting these too.
- We also plan to connect to banks via web scraping.
How do I set up a bank access?
- To set up a bank access, you first have to obtain the provider ID of the bank from AHOI. You send this to AHOI together with your banking credentials.
- For each bank, the field identifiers and the user log in instructions to be provided are different. Please check the provider information for the bank in question.
- AHOI initially sets up all accounts supported by a particular bank access. If you do not need all accounts, just delete the ones you do not need.
Accounts
My accounts are gone. What happened?
- AHOI stores your accounts under the
installationId
. Therefore, you must remember and save theinstallationId
. - AHOI deletes all data under an
installationId
if there have not been any AHOI requests for thisinstallationId
within 90 days
Why do I always have to re-register with AHOI 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 AHOI support?
AHOI basically supports giro-type (i.e., current, checking) and securities accounts. Both account types are also offered by the AHOI Sandbank.
What account types are still planned in AHOI?
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 AHOI Sandbank).
AHOI will automatically update the accounts for a given
installationId
every other hour.To force a manual refresh use the resource
POST /accesses/{ACCESS_ID}/accounts/{ACCOUNT_ID}/refresh
. You will receive a task and once thestate
isSUCCESS
your account will be up to date.
Why am I not receiving new transactions in my AHOI Sandbank accounts?
The AHOI Sandbank accounts currently only create transactions when you register. New transactions are not generated on an ongoing basis. However, you can generate your own transactions by creating transfers to these accounts via AHOI. For example, if you transfer money from one demo account to another demo account, corresponding transactions are created.
Payment transactions / bank transfers / direct debits
What kind of payment transactions does AHOI currently support?
AHOI 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 AHOI Sandbank access
I forgot my password for the AHOI Sandbank. 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 AHOI Sandbank 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 AHOI Sandbank. Under "Settings" you'll find the section "Profile" where you can delete your profile.
Production use of AHOI
I want to use AHOI 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 AHOI 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 AHOI 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 AHOI for my own application as a private individual?
No, private individuals are not allowed to use AHOI in production contexts. As a private individual, you are only allowed to use the AHOI Sandbank with demo accounts.
Engineering / software development
Is there a client SDK for AHOI?
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 AHOI client?
Yes, you can generate a client by using our swagger file, but you will have to do it yourself.
Security
Why does AHOI store my bank access credentials?
AHOI 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 AHOI 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 AHOI. However, these requirements only apply once the application goes live to your customers. On request, we can provide you with the "Security Standard for AHOI 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).
Technical
Do you support Cross-Origin Resource Sharing (CORS) requests?
AHOI is a server-to-server API and is not intended to be used directly from browser. If you want to use AHOI we expect you to connect to it via your own application service.
Are requests to AHOI rate-limited?
Yes, requests to AHOI (/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 will process your request in accordance with our Privacy Policy.
We also welcome your feedback on our documentation.
Glossary
- BaFIN: "Bundesanstalt für Finanzdientleistungsaufsicht"
- BANKING TOKEN: Extended AHOI OAuth2 token
- IBAN: "International Bank Account Number"
- JSON: "JavaScript Object Notation"
- SEPA: "Single Euro Payments Area"
- TAN: "Transaction Authorization Number"
- ZAD: "Zahlungsauslösedienst" defined by PSD2 rules
- ZAG: "Zahlungsdiensteaufsichtsgesetz" defined by German law
- 2FA: "Two Factor Authentication"
- SCA: "Strong Customer Authentication" - requiring 2FA for bank requests