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 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 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 Sandbox Manager
- 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 Sandbox Manager
The first step you need to complete before you can use AHOI 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 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 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 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 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 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 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 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 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 AHOI 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:
- Create a publicly available endpoint for AHOI webhooks
- Register your endpoint URL with the AHOI Sandbox Manager
- Send a test event
- 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.
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 AHOI 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 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 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 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
How to Use Extended Encryption
Overview
Here are the steps to carry out a registration with extended encryption using AHOI:
- Get a registration token
- Retrieve a public key
- Create
X-Ahoi-Session-Security
header - Request a registration
- Extract the
installationId
- 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": "SHA512_WITH_RSA"
}
}
Identifier | Description |
---|---|
RSA_2048_SHA1 | RSA private / public key with 2048-bit key length and OAEP padding. ("RSA/ECB/OAEPWithSHA-1AndMGF1 Padding") |
SHA512_WITH_RSA | SHA512 signature with RSA private / public key with 2048-bit key length and PKCS1 padding. ("SHA512withRSA") |
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 AHOI and vice versa.
The necessary steps to build the header are:
- Generate the symmetric key (AES)
- Decode the public key received from AHOI
- Encrypt the symmetric key with the AHOI public key to secure the session key
- Encode the session key with Base64URL
- Build the JSON string containing
publicKeyId
,sessionKey
andkeySpecification
- 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 AHOI 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 AHOI 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>"
}
}
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 Sandbox Manager 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 Sandbox Manager 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 Sandbox Manager. 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 sandbox system?
Right now, you can only use the AHOI Sandbank.
Why can I only use "AHOI Sandbank" within the sandbox system?
You can use our 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 with the Sandbox Manager. 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.
You have the possibility to create transactions directly in the Sandbox Manager for a demo account.
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.
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 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 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 installationId
s and their associated data for a clientId
at once. Consult the "Delete All Installation Data" section on the overview page.
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 sandbox 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).
How can I tell AHOI 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?
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